Skip to main content

hir/
diagnostics.rs

1//! Re-export diagnostics such that clients of `hir` don't have to depend on
2//! low-level crates.
3//!
4//! This probably isn't the best way to do this -- ideally, diagnostics should
5//! be expressed in terms of hir types themselves.
6use cfg::{CfgExpr, CfgOptions};
7use either::Either;
8use hir_def::{
9    DefWithBodyId, GenericParamId, HasModule, SyntheticSyntax,
10    expr_store::{
11        ExprOrPatPtr, ExpressionStoreSourceMap, hir_assoc_type_binding_to_ast,
12        hir_generic_arg_to_ast, hir_segment_to_ast_segment,
13    },
14    hir::{ExprId, ExprOrPatId, PatId},
15    type_ref::TypeRefId,
16};
17use hir_expand::{HirFileId, InFile, mod_path::ModPath, name::Name};
18use hir_ty::{
19    CastError, ExplicitDropMethodUseKind, InferenceDiagnostic, InferenceTyDiagnosticSource,
20    PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic,
21    db::HirDatabase,
22    diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
23    display::{DisplayTarget, HirDisplay},
24    next_solver::{DbInterner, EarlyBinder},
25    solver_errors::SolverDiagnosticKind,
26};
27use stdx::{impl_from, never};
28use syntax::{
29    AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
30    ast::{self, HasGenericArgs},
31    match_ast,
32};
33use triomphe::Arc;
34
35use crate::{AssocItem, Field, Function, GenericDef, Trait, Type, TypeOwnerId, Variant};
36
37pub use hir_def::VariantId;
38pub use hir_ty::{
39    GenericArgsProhibitedReason, IncorrectGenericsLenKind, ReturnKind,
40    diagnostics::{CaseType, IncorrectCase},
41};
42
43#[derive(Debug, Clone)]
44pub enum SpanAst {
45    Expr(ast::Expr),
46    Pat(ast::Pat),
47    Type(ast::Type),
48}
49const _: () = {
50    use syntax::ast::*;
51    impl_from!(Expr, Pat, Type for SpanAst);
52};
53
54impl From<Either<ast::Expr, ast::Pat>> for SpanAst {
55    fn from(value: Either<ast::Expr, ast::Pat>) -> Self {
56        match value {
57            Either::Left(it) => it.into(),
58            Either::Right(it) => it.into(),
59        }
60    }
61}
62
63impl ast::AstNode for SpanAst {
64    fn can_cast(kind: syntax::SyntaxKind) -> bool {
65        ast::Expr::can_cast(kind) || ast::Pat::can_cast(kind) || ast::Type::can_cast(kind)
66    }
67
68    fn cast(syntax: syntax::SyntaxNode) -> Option<Self> {
69        ast::Expr::cast(syntax.clone())
70            .map(SpanAst::Expr)
71            .or_else(|| ast::Pat::cast(syntax.clone()).map(SpanAst::Pat))
72            .or_else(|| ast::Type::cast(syntax).map(SpanAst::Type))
73    }
74
75    fn syntax(&self) -> &syntax::SyntaxNode {
76        match self {
77            SpanAst::Expr(it) => it.syntax(),
78            SpanAst::Pat(it) => it.syntax(),
79            SpanAst::Type(it) => it.syntax(),
80        }
81    }
82}
83
84pub type SpanSyntax = InFile<AstPtr<SpanAst>>;
85
86macro_rules! diagnostics {
87    ($AnyDiagnostic:ident <$db:lifetime> -> $($diag:ident $(<$lt:lifetime>)?,)*) => {
88        #[derive(Debug)]
89        pub enum $AnyDiagnostic<$db> {$(
90            $diag(Box<$diag $(<$lt>)?>),
91        )*}
92
93        $(
94            impl<$db> From<$diag $(<$lt>)?> for $AnyDiagnostic<$db> {
95                fn from(d: $diag $(<$lt>)?) -> $AnyDiagnostic<$db> {
96                    $AnyDiagnostic::$diag(Box::new(d))
97                }
98            }
99        )*
100    };
101}
102
103diagnostics![AnyDiagnostic<'db> ->
104    ArrayPatternWithoutFixedLength,
105    AwaitOutsideOfAsync,
106    BreakOutsideOfLoop,
107    CannotBeDereferenced<'db>,
108    UnaryOperatorCannotBeApplied<'db>,
109    CannotImplicitlyDerefTraitObject<'db>,
110    CannotIndexInto<'db>,
111    CastToUnsized<'db>,
112    ExpectedArrayOrSlicePat<'db>,
113    ExpectedFunction<'db>,
114    ExplicitDropMethodUse,
115    FruInDestructuringAssignment,
116    FunctionalRecordUpdateOnNonStruct,
117    GenericDefaultRefersToSelf,
118    InactiveCode,
119    IncoherentImpl,
120    IncorrectCase,
121    IncorrectGenericsLen,
122    IncorrectGenericsOrder,
123    InferVarsNotAllowed,
124    InvalidCast<'db>,
125    InvalidDeriveTarget,
126    InvalidLhsOfAssignment,
127    InvalidRangePatType,
128    MacroDefError,
129    MacroError,
130    MacroExpansionParseError,
131    MalformedDerive,
132    MethodCallIllegalSizedBound,
133    MismatchedArgCount,
134    MismatchedTupleStructPatArgCount,
135    MissingFields,
136    MissingMatchArms,
137    MissingUnsafe,
138    MutRefInImmRefPat,
139    MutableRefBinding,
140    NonExhaustiveLet,
141    NonExhaustiveRecordExpr,
142    NonExhaustiveRecordPat,
143    NoSuchField,
144    MismatchedArrayPatLen,
145    DuplicateField,
146    PatternArgInExternFn,
147    PrivateAssocItem,
148    PrivateField,
149    RemoveTrailingReturn,
150    RemoveUnnecessaryElse,
151    UnusedMustUse<'db>,
152    ReplaceFilterMapNextWithFindMap,
153    TraitImplIncorrectSafety,
154    TraitImplMissingAssocItems,
155    TraitImplOrphan,
156    TraitImplRedundantAssocItems,
157    TypedHole<'db>,
158    TypeMismatch<'db>,
159    UndeclaredLabel,
160    UnimplementedBuiltinMacro,
161    UnreachableLabel,
162    UnresolvedAssocItem,
163    UnresolvedExternCrate,
164    UnresolvedField<'db>,
165    UnresolvedImport,
166    UnresolvedMacroCall,
167    UnresolvedMethodCall<'db>,
168    UnresolvedModule,
169    UnresolvedIdent,
170    GenericArgsProhibited,
171    ParenthesizedGenericArgsWithoutFnTrait,
172    BadRtn,
173    MissingLifetime,
174    ElidedLifetimesInPath,
175    TypeMustBeKnown<'db>,
176    UnionExprMustHaveExactlyOneField,
177    UnionPatMustHaveExactlyOneField,
178    UnionPatHasRest,
179    UnimplementedTrait<'db>,
180    YieldOutsideCoroutine,
181    ReturnOutsideFunction,
182];
183
184#[derive(Debug)]
185pub struct BreakOutsideOfLoop {
186    pub expr: InFile<ExprOrPatPtr>,
187    pub is_break: bool,
188    pub bad_value_break: bool,
189}
190
191#[derive(Debug)]
192pub struct TypedHole<'db> {
193    pub expr: InFile<ExprOrPatPtr>,
194    pub expected: Type<'db>,
195}
196
197#[derive(Debug)]
198pub struct UnresolvedModule {
199    pub decl: InFile<AstPtr<ast::Module>>,
200    pub candidates: Box<[String]>,
201}
202
203#[derive(Debug)]
204pub struct UnresolvedExternCrate {
205    pub decl: InFile<AstPtr<ast::ExternCrate>>,
206}
207
208#[derive(Debug)]
209pub struct UnresolvedImport {
210    pub decl: InFile<AstPtr<ast::UseTree>>,
211}
212
213#[derive(Debug, Clone, Eq, PartialEq)]
214pub struct UnresolvedMacroCall {
215    pub range: InFile<TextRange>,
216    pub path: ModPath,
217    pub is_bang: bool,
218}
219#[derive(Debug, Clone, Eq, PartialEq)]
220pub struct UnreachableLabel {
221    pub node: InFile<AstPtr<ast::Lifetime>>,
222    pub name: Name,
223}
224
225#[derive(Debug)]
226pub struct AwaitOutsideOfAsync {
227    pub node: InFile<AstPtr<ast::AwaitExpr>>,
228    pub location: String,
229}
230
231#[derive(Debug, Clone, Eq, PartialEq)]
232pub struct UndeclaredLabel {
233    pub node: InFile<AstPtr<ast::Lifetime>>,
234    pub name: Name,
235}
236
237#[derive(Debug, Clone, Eq, PartialEq)]
238pub struct InactiveCode {
239    pub node: InFile<SyntaxNodePtr>,
240    pub cfg: CfgExpr,
241    pub opts: CfgOptions,
242}
243
244#[derive(Debug, Clone, Eq, PartialEq)]
245pub struct MacroError {
246    pub range: InFile<TextRange>,
247    pub message: String,
248    pub error: bool,
249    pub kind: &'static str,
250}
251
252#[derive(Debug, Clone, Eq, PartialEq)]
253pub struct MacroExpansionParseError {
254    pub range: InFile<TextRange>,
255    pub errors: Arc<[SyntaxError]>,
256}
257
258#[derive(Debug, Clone, Eq, PartialEq)]
259pub struct MacroDefError {
260    pub node: InFile<AstPtr<ast::Macro>>,
261    pub message: String,
262    pub name: Option<TextRange>,
263}
264
265#[derive(Debug)]
266pub struct UnimplementedBuiltinMacro {
267    pub node: InFile<SyntaxNodePtr>,
268}
269
270#[derive(Debug)]
271pub struct InvalidDeriveTarget {
272    pub range: InFile<TextRange>,
273}
274
275#[derive(Debug)]
276pub struct MalformedDerive {
277    pub range: InFile<TextRange>,
278}
279
280#[derive(Debug)]
281pub struct NoSuchField {
282    pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
283    pub private: Option<Field>,
284    pub variant: VariantId,
285}
286
287#[derive(Debug)]
288pub struct DuplicateField {
289    pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
290    pub variant: Variant,
291}
292
293#[derive(Debug)]
294pub struct PrivateAssocItem {
295    pub expr_or_pat: InFile<ExprOrPatPtr>,
296    pub item: AssocItem,
297}
298
299#[derive(Debug)]
300pub struct MismatchedTupleStructPatArgCount {
301    pub expr_or_pat: InFile<ExprOrPatPtr>,
302    pub expected: usize,
303    pub found: usize,
304}
305
306#[derive(Debug)]
307pub struct MismatchedArrayPatLen {
308    pub pat: InFile<ExprOrPatPtr>,
309    pub expected: u64,
310    pub found: u64,
311    pub has_rest: bool,
312}
313
314#[derive(Debug)]
315pub struct ArrayPatternWithoutFixedLength {
316    pub pat: InFile<ExprOrPatPtr>,
317}
318
319#[derive(Debug)]
320pub struct ExpectedArrayOrSlicePat<'db> {
321    pub pat: InFile<ExprOrPatPtr>,
322    pub found: Type<'db>,
323}
324
325#[derive(Debug)]
326pub struct InvalidRangePatType {
327    pub pat: InFile<ExprOrPatPtr>,
328}
329
330#[derive(Debug)]
331pub struct ExpectedFunction<'db> {
332    pub call: InFile<ExprOrPatPtr>,
333    pub found: Type<'db>,
334}
335
336#[derive(Debug)]
337pub struct CannotBeDereferenced<'db> {
338    pub expr: InFile<ExprOrPatPtr>,
339    pub found: Type<'db>,
340}
341
342#[derive(Debug)]
343pub struct UnaryOperatorCannotBeApplied<'db> {
344    pub expr: InFile<ExprOrPatPtr>,
345    pub op: ast::UnaryOp,
346    pub found: Type<'db>,
347}
348
349#[derive(Debug)]
350pub struct MutRefInImmRefPat {
351    pub pat: InFile<ExprOrPatPtr>,
352}
353
354#[derive(Debug)]
355pub struct CannotImplicitlyDerefTraitObject<'db> {
356    pub pat: InFile<ExprOrPatPtr>,
357    pub found: Type<'db>,
358}
359
360#[derive(Debug)]
361pub struct CannotIndexInto<'db> {
362    pub expr: InFile<ExprOrPatPtr>,
363    pub found: Type<'db>,
364}
365
366#[derive(Debug)]
367pub struct ExplicitDropMethodUse {
368    pub expr_or_path: Either<InFile<AstPtr<ast::MethodCallExpr>>, InFile<AstPtr<ast::Path>>>,
369}
370
371#[derive(Debug)]
372pub struct FruInDestructuringAssignment {
373    pub node: InFile<AstPtr<ast::Expr>>,
374}
375
376#[derive(Debug)]
377pub struct FunctionalRecordUpdateOnNonStruct {
378    pub base_expr: InFile<ExprOrPatPtr>,
379}
380
381#[derive(Debug)]
382pub struct UnresolvedField<'db> {
383    pub expr: InFile<ExprOrPatPtr>,
384    pub receiver: Type<'db>,
385    pub name: Name,
386    pub method_with_same_name_exists: bool,
387}
388
389#[derive(Debug)]
390pub struct UnresolvedMethodCall<'db> {
391    pub expr: InFile<ExprOrPatPtr>,
392    pub receiver: Type<'db>,
393    pub name: Name,
394    pub field_with_same_name: Option<Type<'db>>,
395    pub assoc_func_with_same_name: Option<Function>,
396}
397
398#[derive(Debug)]
399pub struct UnresolvedAssocItem {
400    pub expr_or_pat: InFile<ExprOrPatPtr>,
401}
402
403#[derive(Debug)]
404pub struct UnresolvedIdent {
405    pub node: InFile<(ExprOrPatPtr, Option<TextRange>)>,
406}
407
408#[derive(Debug)]
409pub struct PrivateField {
410    pub expr: InFile<ExprOrPatPtr>,
411    pub field: Field,
412}
413
414#[derive(Debug, Clone, Copy, PartialEq, Eq)]
415pub enum UnsafeLint {
416    HardError,
417    UnsafeOpInUnsafeFn,
418    DeprecatedSafe2024,
419}
420
421#[derive(Debug)]
422pub struct MissingUnsafe {
423    pub node: InFile<ExprOrPatPtr>,
424    pub lint: UnsafeLint,
425    pub reason: UnsafetyReason,
426}
427
428#[derive(Debug)]
429pub struct MissingFields {
430    pub file: HirFileId,
431    pub field_list_parent: AstPtr<Either<ast::RecordExpr, ast::RecordPat>>,
432    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
433    pub missed_fields: Vec<(Name, Field)>,
434}
435
436#[derive(Debug)]
437pub struct ReplaceFilterMapNextWithFindMap {
438    pub file: HirFileId,
439    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
440    pub next_expr: AstPtr<ast::Expr>,
441}
442
443#[derive(Debug)]
444pub struct MismatchedArgCount {
445    pub call_expr: InFile<ExprOrPatPtr>,
446    pub expected: usize,
447    pub found: usize,
448    /// True when the call is through a `Fn`/`FnMut`/`FnOnce` trait (E0057)
449    /// rather than a regular function call (E0061).
450    pub is_fn_trait_call: bool,
451}
452
453#[derive(Debug)]
454pub struct MissingMatchArms {
455    pub scrutinee_expr: InFile<AstPtr<ast::Expr>>,
456    pub uncovered_patterns: String,
457}
458
459#[derive(Debug)]
460pub struct NonExhaustiveLet {
461    pub pat: InFile<AstPtr<ast::Pat>>,
462    pub uncovered_patterns: String,
463}
464
465#[derive(Debug)]
466pub struct NonExhaustiveRecordExpr {
467    pub expr: InFile<ExprOrPatPtr>,
468}
469
470#[derive(Debug)]
471pub struct NonExhaustiveRecordPat {
472    pub pat: InFile<ExprOrPatPtr>,
473    pub variant: Variant,
474}
475
476#[derive(Debug)]
477pub struct TypeMismatch<'db> {
478    pub expr_or_pat: InFile<ExprOrPatPtr>,
479    pub expected: Type<'db>,
480    pub actual: Type<'db>,
481}
482
483#[derive(Debug, PartialEq, Eq)]
484pub struct IncoherentImpl {
485    pub file_id: HirFileId,
486    pub impl_: AstPtr<ast::Impl>,
487}
488
489#[derive(Debug, PartialEq, Eq)]
490pub struct TraitImplOrphan {
491    pub file_id: HirFileId,
492    pub impl_: AstPtr<ast::Impl>,
493}
494
495// FIXME: Split this off into the corresponding 4 rustc errors
496#[derive(Debug, PartialEq, Eq)]
497pub struct TraitImplIncorrectSafety {
498    pub file_id: HirFileId,
499    pub impl_: AstPtr<ast::Impl>,
500    pub should_be_safe: bool,
501}
502
503#[derive(Debug, PartialEq, Eq)]
504pub struct TraitImplMissingAssocItems {
505    pub file_id: HirFileId,
506    pub impl_: AstPtr<ast::Impl>,
507    pub missing: Vec<(Name, AssocItem)>,
508}
509
510#[derive(Debug, PartialEq, Eq)]
511pub struct TraitImplRedundantAssocItems {
512    pub file_id: HirFileId,
513    pub trait_: Trait,
514    pub impl_: AstPtr<ast::Impl>,
515    pub assoc_item: (Name, AssocItem),
516}
517
518#[derive(Debug)]
519pub struct RemoveTrailingReturn {
520    pub return_expr: InFile<AstPtr<ast::ReturnExpr>>,
521}
522
523#[derive(Debug)]
524pub struct RemoveUnnecessaryElse {
525    pub if_expr: InFile<AstPtr<ast::IfExpr>>,
526}
527
528#[derive(Debug)]
529pub struct UnusedMustUse<'db> {
530    pub expr: InFile<ExprOrPatPtr>,
531    pub message: Option<&'db str>,
532}
533
534#[derive(Debug)]
535pub struct CastToUnsized<'db> {
536    pub expr: InFile<ExprOrPatPtr>,
537    pub cast_ty: Type<'db>,
538}
539
540#[derive(Debug)]
541pub struct InvalidCast<'db> {
542    pub expr: InFile<ExprOrPatPtr>,
543    pub error: CastError,
544    pub expr_ty: Type<'db>,
545    pub cast_ty: Type<'db>,
546}
547
548#[derive(Debug)]
549pub struct GenericArgsProhibited {
550    pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>,
551    pub reason: GenericArgsProhibitedReason,
552}
553
554#[derive(Debug)]
555pub struct ParenthesizedGenericArgsWithoutFnTrait {
556    pub args: InFile<AstPtr<ast::ParenthesizedArgList>>,
557}
558
559#[derive(Debug)]
560pub struct BadRtn {
561    pub rtn: InFile<AstPtr<ast::ReturnTypeSyntax>>,
562}
563
564#[derive(Debug)]
565pub struct InferVarsNotAllowed {
566    pub node: InFile<SyntaxNodePtr>,
567}
568
569#[derive(Debug)]
570pub struct IncorrectGenericsLen {
571    /// Points at the name if there are no generics.
572    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
573    pub kind: IncorrectGenericsLenKind,
574    pub provided: u32,
575    pub expected: u32,
576    pub def: GenericDef,
577}
578
579#[derive(Debug)]
580pub struct MissingLifetime {
581    /// Points at the name if there are no generics.
582    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
583    pub expected: u32,
584    pub def: GenericDef,
585}
586
587#[derive(Debug)]
588pub struct ElidedLifetimesInPath {
589    /// Points at the name if there are no generics.
590    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
591    pub expected: u32,
592    pub def: GenericDef,
593    pub hard_error: bool,
594}
595
596#[derive(Debug)]
597pub struct TypeMustBeKnown<'db> {
598    pub at_point: SpanSyntax,
599    pub top_term: Option<Either<Type<'db>, String>>,
600}
601
602#[derive(Debug, Clone, Copy, PartialEq, Eq)]
603pub enum GenericArgKind {
604    Lifetime,
605    Type,
606    Const,
607}
608
609impl GenericArgKind {
610    fn from_id(id: GenericParamId) -> Self {
611        match id {
612            GenericParamId::TypeParamId(_) => GenericArgKind::Type,
613            GenericParamId::ConstParamId(_) => GenericArgKind::Const,
614            GenericParamId::LifetimeParamId(_) => GenericArgKind::Lifetime,
615        }
616    }
617}
618
619#[derive(Debug)]
620pub struct IncorrectGenericsOrder {
621    pub provided_arg: InFile<AstPtr<ast::GenericArg>>,
622    pub expected_kind: GenericArgKind,
623}
624
625#[derive(Debug)]
626pub struct GenericDefaultRefersToSelf {
627    /// The `Self` segment.
628    pub segment: InFile<AstPtr<ast::PathSegment>>,
629}
630
631#[derive(Debug)]
632pub struct UnionExprMustHaveExactlyOneField {
633    pub expr: InFile<ExprOrPatPtr>,
634}
635
636#[derive(Debug)]
637pub struct UnionPatMustHaveExactlyOneField {
638    pub pat: InFile<ExprOrPatPtr>,
639}
640
641#[derive(Debug)]
642pub struct UnionPatHasRest {
643    pub pat: InFile<ExprOrPatPtr>,
644}
645
646#[derive(Debug)]
647pub struct InvalidLhsOfAssignment {
648    pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
649}
650
651#[derive(Debug)]
652pub struct MethodCallIllegalSizedBound {
653    pub call_expr: InFile<ExprOrPatPtr>,
654}
655
656#[derive(Debug)]
657pub struct PatternArgInExternFn {
658    pub node: InFile<AstPtr<ast::Pat>>,
659}
660
661#[derive(Debug)]
662pub struct UnimplementedTrait<'db> {
663    pub span: SpanSyntax,
664    pub trait_predicate: crate::TraitPredicate<'db>,
665    pub parent_trait_predicates: Vec<crate::TraitPredicate<'db>>,
666}
667
668#[derive(Debug)]
669pub struct MutableRefBinding {
670    pub pat: InFile<ExprOrPatPtr>,
671}
672
673#[derive(Debug)]
674pub struct YieldOutsideCoroutine {
675    pub expr: InFile<ExprOrPatPtr>,
676}
677
678#[derive(Debug)]
679pub struct ReturnOutsideFunction {
680    pub expr: InFile<ExprOrPatPtr>,
681    pub kind: ReturnKind,
682}
683
684impl<'db> AnyDiagnostic<'db> {
685    pub(crate) fn body_validation_diagnostic(
686        db: &'db dyn HirDatabase,
687        diagnostic: BodyValidationDiagnostic<'db>,
688        source_map: &hir_def::expr_store::BodySourceMap,
689    ) -> Option<AnyDiagnostic<'db>> {
690        match diagnostic {
691            BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
692                let variant_data = variant.fields(db);
693                let missed_fields = missed_fields
694                    .into_iter()
695                    .map(|idx| {
696                        (
697                            variant_data.fields()[idx].name.clone(),
698                            Field { parent: variant.into(), id: idx },
699                        )
700                    })
701                    .collect();
702
703                let record = match record {
704                    Either::Left(record_expr) => source_map.expr_syntax(record_expr).ok()?,
705                    Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
706                };
707                let file = record.file_id;
708                let root = record.file_syntax(db);
709                match record.value.to_node(&root) {
710                    Either::Left(ast::Expr::RecordExpr(record_expr))
711                        if record_expr.record_expr_field_list().is_some() =>
712                    {
713                        let field_list_parent_path =
714                            record_expr.path().map(|path| AstPtr::new(&path));
715                        return Some(
716                            MissingFields {
717                                file,
718                                field_list_parent: AstPtr::new(&Either::Left(record_expr)),
719                                field_list_parent_path,
720                                missed_fields,
721                            }
722                            .into(),
723                        );
724                    }
725                    Either::Right(ast::Pat::RecordPat(record_pat))
726                        if record_pat.record_pat_field_list().is_some() =>
727                    {
728                        let field_list_parent_path =
729                            record_pat.path().map(|path| AstPtr::new(&path));
730                        return Some(
731                            MissingFields {
732                                file,
733                                field_list_parent: AstPtr::new(&Either::Right(record_pat)),
734                                field_list_parent_path,
735                                missed_fields,
736                            }
737                            .into(),
738                        );
739                    }
740                    _ => {}
741                }
742            }
743            BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
744                if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
745                    return Some(
746                        ReplaceFilterMapNextWithFindMap {
747                            file: next_source_ptr.file_id,
748                            next_expr: next_source_ptr.value.cast()?,
749                        }
750                        .into(),
751                    );
752                }
753            }
754            BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
755                if let Ok(source_ptr) = source_map.expr_syntax(match_expr)
756                    && let root = source_ptr.file_syntax(db)
757                    && let Either::Left(ast::Expr::MatchExpr(match_expr)) =
758                        source_ptr.value.to_node(&root)
759                    && let Some(scrut_expr) = match_expr.expr()
760                    && match_expr.match_arm_list().is_some()
761                {
762                    return Some(
763                        MissingMatchArms {
764                            scrutinee_expr: InFile::new(
765                                source_ptr.file_id,
766                                AstPtr::new(&scrut_expr),
767                            ),
768                            uncovered_patterns,
769                        }
770                        .into(),
771                    );
772                }
773            }
774            BodyValidationDiagnostic::NonExhaustiveLet { pat, uncovered_patterns } => {
775                if let Ok(source_ptr) = source_map.pat_syntax(pat)
776                    && let Some(ast_pat) = source_ptr.value.cast::<ast::Pat>()
777                {
778                    return Some(
779                        NonExhaustiveLet {
780                            pat: InFile::new(source_ptr.file_id, ast_pat),
781                            uncovered_patterns,
782                        }
783                        .into(),
784                    );
785                }
786            }
787            BodyValidationDiagnostic::RemoveTrailingReturn { return_expr } => {
788                if let Ok(source_ptr) = source_map.expr_syntax(return_expr)
789                    // Filters out desugared return expressions (e.g. desugared try operators).
790                    && let Some(ptr) = source_ptr.value.cast::<ast::ReturnExpr>()
791                {
792                    return Some(
793                        RemoveTrailingReturn { return_expr: InFile::new(source_ptr.file_id, ptr) }
794                            .into(),
795                    );
796                }
797            }
798            BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr } => {
799                if let Ok(source_ptr) = source_map.expr_syntax(if_expr)
800                    && let Some(ptr) = source_ptr.value.cast::<ast::IfExpr>()
801                {
802                    return Some(
803                        RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) }
804                            .into(),
805                    );
806                }
807            }
808            BodyValidationDiagnostic::UnusedMustUse { expr, message } => {
809                if let Ok(source_ptr) = source_map.expr_syntax(expr) {
810                    return Some(UnusedMustUse { expr: source_ptr, message }.into());
811                }
812            }
813        }
814        None
815    }
816
817    pub(crate) fn inference_diagnostic(
818        db: &'db dyn HirDatabase,
819        def: DefWithBodyId,
820        d: &'db InferenceDiagnostic,
821        source_map: &hir_def::expr_store::BodySourceMap,
822        sig_map: &hir_def::expr_store::ExpressionStoreSourceMap,
823        type_owner: TypeOwnerId<'db>,
824    ) -> Option<AnyDiagnostic<'db>> {
825        let expr_syntax = |expr| Self::expr_syntax(expr, source_map);
826        let pat_syntax = |pat| Self::pat_syntax(pat, source_map);
827        let expr_or_pat_syntax = |id| match id {
828            ExprOrPatId::ExprId(expr) => expr_syntax(expr),
829            ExprOrPatId::PatId(pat) => pat_syntax(pat),
830        };
831        let new_ty = |ty| Type { owner: type_owner, ty: EarlyBinder::bind(ty) };
832        let span_syntax = |span| Self::span_syntax(span, source_map);
833        Some(match d {
834            &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
835                let expr_or_pat = match expr.unpack() {
836                    ExprOrPatId::ExprId(expr) => {
837                        source_map.field_syntax(expr).map(AstPtr::wrap_left)
838                    }
839                    ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
840                };
841                let private = private.map(|id| Field { id, parent: variant.into() });
842                NoSuchField { field: expr_or_pat, private, variant }.into()
843            }
844            &InferenceDiagnostic::MismatchedArrayPatLen { pat, expected, found, has_rest } => {
845                let pat = pat_syntax(pat)?.map(Into::into);
846                MismatchedArrayPatLen { pat, expected, found, has_rest }.into()
847            }
848            &InferenceDiagnostic::ArrayPatternWithoutFixedLength { pat } => {
849                let pat = pat_syntax(pat)?.map(Into::into);
850                ArrayPatternWithoutFixedLength { pat }.into()
851            }
852            InferenceDiagnostic::ExpectedArrayOrSlicePat { pat, found } => {
853                let pat = pat_syntax(*pat)?.map(Into::into);
854                ExpectedArrayOrSlicePat {
855                    pat,
856                    found: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) },
857                }
858                .into()
859            }
860            &InferenceDiagnostic::InvalidRangePatType { pat } => {
861                let pat = pat_syntax(pat)?.map(Into::into);
862                InvalidRangePatType { pat }.into()
863            }
864            &InferenceDiagnostic::DuplicateField { field: expr, variant } => {
865                let expr_or_pat = match expr.unpack() {
866                    ExprOrPatId::ExprId(expr) => {
867                        source_map.field_syntax(expr).map(AstPtr::wrap_left)
868                    }
869                    ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
870                };
871                DuplicateField { field: expr_or_pat, variant: variant.into() }.into()
872            }
873            &InferenceDiagnostic::MismatchedArgCount {
874                call_expr,
875                expected,
876                found,
877                is_fn_trait_call,
878            } => MismatchedArgCount {
879                call_expr: expr_syntax(call_expr)?,
880                expected,
881                found,
882                is_fn_trait_call,
883            }
884            .into(),
885            &InferenceDiagnostic::PrivateField { expr, field } => {
886                let expr = expr_syntax(expr)?;
887                let field = field.into();
888                PrivateField { expr, field }.into()
889            }
890            &InferenceDiagnostic::PrivateAssocItem { id, item } => {
891                let expr_or_pat = expr_or_pat_syntax(id.unpack())?;
892                let item = item.into();
893                PrivateAssocItem { expr_or_pat, item }.into()
894            }
895            InferenceDiagnostic::ExpectedFunction { call_expr, found } => {
896                let call_expr = expr_syntax(*call_expr)?;
897                ExpectedFunction { call: call_expr, found: new_ty(found.as_ref()) }.into()
898            }
899            InferenceDiagnostic::UnresolvedField {
900                expr,
901                receiver,
902                name,
903                method_with_same_name_exists,
904            } => {
905                let expr = expr_syntax(*expr)?;
906                UnresolvedField {
907                    expr,
908                    name: name.clone(),
909                    receiver: new_ty(receiver.as_ref()),
910                    method_with_same_name_exists: *method_with_same_name_exists,
911                }
912                .into()
913            }
914            InferenceDiagnostic::UnresolvedMethodCall {
915                expr,
916                receiver,
917                name,
918                field_with_same_name,
919                assoc_func_with_same_name,
920            } => {
921                let expr = expr_syntax(*expr)?;
922                UnresolvedMethodCall {
923                    expr,
924                    name: name.clone(),
925                    receiver: new_ty(receiver.as_ref()),
926                    field_with_same_name: field_with_same_name
927                        .as_ref()
928                        .map(|ty| new_ty(ty.as_ref())),
929                    assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into),
930                }
931                .into()
932            }
933            &InferenceDiagnostic::UnresolvedAssocItem { id } => {
934                let expr_or_pat = expr_or_pat_syntax(id.unpack())?;
935                UnresolvedAssocItem { expr_or_pat }.into()
936            }
937            &InferenceDiagnostic::UnresolvedIdent { id } => {
938                let node = match id.unpack() {
939                    ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) {
940                        Ok(syntax) => syntax.map(|it| (it, None)),
941                        Err(SyntheticSyntax) => source_map
942                            .format_args_implicit_capture(id)?
943                            .map(|(node, range)| (node.wrap_left(), Some(range))),
944                    },
945                    ExprOrPatId::PatId(id) => pat_syntax(id)?.map(|it| (it, None)),
946                };
947                UnresolvedIdent { node }.into()
948            }
949            &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
950                let expr = expr_syntax(expr)?;
951                BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()
952            }
953            &InferenceDiagnostic::NonExhaustiveRecordExpr { expr } => {
954                NonExhaustiveRecordExpr { expr: expr_syntax(expr)? }.into()
955            }
956            &InferenceDiagnostic::NonExhaustiveRecordPat { pat, variant } => {
957                let pat = pat_syntax(pat)?.map(Into::into);
958                NonExhaustiveRecordPat { pat, variant: variant.into() }.into()
959            }
960            &InferenceDiagnostic::UnionPatMustHaveExactlyOneField { pat } => {
961                let pat = pat_syntax(pat)?.map(Into::into);
962                UnionPatMustHaveExactlyOneField { pat }.into()
963            }
964            &InferenceDiagnostic::UnionPatHasRest { pat } => {
965                let pat = pat_syntax(pat)?.map(Into::into);
966                UnionPatHasRest { pat }.into()
967            }
968            &InferenceDiagnostic::FunctionalRecordUpdateOnNonStruct { base_expr } => {
969                FunctionalRecordUpdateOnNonStruct { base_expr: expr_syntax(base_expr)? }.into()
970            }
971            InferenceDiagnostic::TypedHole { expr, expected } => {
972                let expr = expr_syntax(*expr)?;
973                TypedHole { expr, expected: new_ty(expected.as_ref()) }.into()
974            }
975            &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => {
976                let InFile { file_id, value } = pat_syntax(pat)?;
977                // cast from Either<Pat, SelfParam> -> Either<_, Pat>
978                let ptr = AstPtr::try_from_raw(value.syntax_node_ptr())?;
979                let expr_or_pat = InFile { file_id, value: ptr };
980                MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into()
981            }
982            InferenceDiagnostic::CastToUnsized { expr, cast_ty } => {
983                let expr = expr_syntax(*expr)?;
984                CastToUnsized { expr, cast_ty: new_ty(cast_ty.as_ref()) }.into()
985            }
986            InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => {
987                let expr = expr_syntax(*expr)?;
988                let expr_ty = new_ty(expr_ty.as_ref());
989                let cast_ty = new_ty(cast_ty.as_ref());
990                InvalidCast { expr, error: *error, expr_ty, cast_ty }.into()
991            }
992            InferenceDiagnostic::CannotBeDereferenced { expr, found } => {
993                let expr = expr_syntax(*expr)?;
994                CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into()
995            }
996            InferenceDiagnostic::UnaryOperatorCannotBeApplied { expr, op, found } => {
997                let expr = expr_syntax(*expr)?;
998                UnaryOperatorCannotBeApplied { expr, op: *op, found: new_ty(found.as_ref()) }.into()
999            }
1000            InferenceDiagnostic::MutRefInImmRefPat { pat } => {
1001                let pat = pat_syntax(*pat)?.map(Into::into);
1002                MutRefInImmRefPat { pat }.into()
1003            }
1004            InferenceDiagnostic::CannotImplicitlyDerefTraitObject { pat, found } => {
1005                let pat = pat_syntax(*pat)?.map(Into::into);
1006                CannotImplicitlyDerefTraitObject { pat, found: new_ty(found.as_ref()) }.into()
1007            }
1008            InferenceDiagnostic::CannotIndexInto { expr, found } => {
1009                let expr = expr_syntax(*expr)?;
1010                CannotIndexInto { expr, found: new_ty(found.as_ref()) }.into()
1011            }
1012            InferenceDiagnostic::TyDiagnostic { source, diag } => {
1013                let source_map = match source {
1014                    InferenceTyDiagnosticSource::Body => source_map,
1015                    InferenceTyDiagnosticSource::Signature => sig_map,
1016                };
1017                Self::ty_diagnostic(diag, source_map, db)?
1018            }
1019            InferenceDiagnostic::PathDiagnostic { node, diag } => {
1020                let source = expr_or_pat_syntax(node.unpack())?;
1021                let syntax = source.value.to_node(&source.file_id.parse_or_expand(db));
1022                let path = match_ast! {
1023                    match (syntax.syntax()) {
1024                        ast::RecordExpr(it) => it.path()?,
1025                        ast::RecordPat(it) => it.path()?,
1026                        ast::TupleStructPat(it) => it.path()?,
1027                        ast::PathExpr(it) => it.path()?,
1028                        ast::PathPat(it) => it.path()?,
1029                        _ => return None,
1030                    }
1031                };
1032                Self::path_diagnostic(diag, source.with_value(path))?
1033            }
1034            &InferenceDiagnostic::MethodCallIncorrectGenericsLen {
1035                expr,
1036                provided_count,
1037                expected_count,
1038                kind,
1039                def,
1040            } => {
1041                let syntax = expr_syntax(expr)?;
1042                let file_id = syntax.file_id;
1043                let syntax =
1044                    syntax.with_value(syntax.value.cast::<ast::MethodCallExpr>()?).to_node(db);
1045                let generics_or_name = syntax
1046                    .generic_arg_list()
1047                    .map(Either::Left)
1048                    .or_else(|| syntax.name_ref().map(Either::Right))?;
1049                let generics_or_name = InFile::new(file_id, AstPtr::new(&generics_or_name));
1050                IncorrectGenericsLen {
1051                    generics_or_segment: generics_or_name,
1052                    kind,
1053                    provided: provided_count,
1054                    expected: expected_count,
1055                    def: def.into(),
1056                }
1057                .into()
1058            }
1059            &InferenceDiagnostic::MethodCallIncorrectGenericsOrder {
1060                expr,
1061                param_id,
1062                arg_idx,
1063                has_self_arg,
1064            } => {
1065                let syntax = expr_syntax(expr)?;
1066                let file_id = syntax.file_id;
1067                let syntax =
1068                    syntax.with_value(syntax.value.cast::<ast::MethodCallExpr>()?).to_node(db);
1069                let generic_args = syntax.generic_arg_list()?;
1070                let provided_arg = hir_generic_arg_to_ast(&generic_args, arg_idx, has_self_arg)?;
1071                let provided_arg = InFile::new(file_id, AstPtr::new(&provided_arg));
1072                let expected_kind = GenericArgKind::from_id(param_id);
1073                IncorrectGenericsOrder { provided_arg, expected_kind }.into()
1074            }
1075            &InferenceDiagnostic::InvalidLhsOfAssignment { lhs } => {
1076                let lhs = expr_syntax(lhs)?;
1077                InvalidLhsOfAssignment { lhs }.into()
1078            }
1079            &InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr } => {
1080                MethodCallIllegalSizedBound { call_expr: expr_syntax(call_expr)? }.into()
1081            }
1082            &InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => {
1083                let at_point = span_syntax(at_point)?;
1084                let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() {
1085                    rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(new_ty(ty)),
1086                    // FIXME: Printing the const to string is definitely not the correct thing to do here.
1087                    rustc_type_ir::GenericArgKind::Const(konst) => Either::Right(
1088                        konst.display(db, DisplayTarget::from_crate(db, def.krate(db))).to_string(),
1089                    ),
1090                    rustc_type_ir::GenericArgKind::Lifetime(_) => {
1091                        unreachable!("we currently don't emit TypeMustBeKnown for lifetimes")
1092                    }
1093                });
1094                TypeMustBeKnown { at_point, top_term }.into()
1095            }
1096            &InferenceDiagnostic::UnionExprMustHaveExactlyOneField { expr } => {
1097                let expr = expr_syntax(expr)?;
1098                UnionExprMustHaveExactlyOneField { expr }.into()
1099            }
1100            InferenceDiagnostic::TypeMismatch { node, expected, found } => {
1101                let expr_or_pat = expr_or_pat_syntax(node.unpack())?;
1102                TypeMismatch {
1103                    expr_or_pat,
1104                    expected: Type { owner: type_owner, ty: EarlyBinder::bind(expected.as_ref()) },
1105                    actual: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) },
1106                }
1107                .into()
1108            }
1109            InferenceDiagnostic::SolverDiagnostic(d) => {
1110                let span = span_syntax(d.span)?;
1111                Self::solver_diagnostic(db, &d.kind, span, type_owner)?
1112            }
1113            InferenceDiagnostic::ExplicitDropMethodUse { kind } => {
1114                let expr_or_path = match kind {
1115                    ExplicitDropMethodUseKind::MethodCall(expr) => {
1116                        let expr = expr_syntax(*expr)?;
1117                        let expr = expr.with_value(expr.value.cast::<ast::MethodCallExpr>()?);
1118                        Either::Left(expr)
1119                    }
1120                    ExplicitDropMethodUseKind::Path(path_expr_id) => {
1121                        let syntax = expr_or_pat_syntax(path_expr_id.unpack())?;
1122                        let file_id = syntax.file_id;
1123                        let syntax =
1124                            syntax.with_value(syntax.value.cast::<ast::PathExpr>()?).to_node(db);
1125                        let path = syntax.path()?;
1126                        let path = InFile::new(file_id, AstPtr::new(&path));
1127                        Either::Right(path)
1128                    }
1129                };
1130                ExplicitDropMethodUse { expr_or_path }.into()
1131            }
1132            InferenceDiagnostic::MutableRefBinding { pat } => {
1133                let pat = pat_syntax(*pat)?.map(Into::into);
1134                MutableRefBinding { pat }.into()
1135            }
1136            &InferenceDiagnostic::YieldOutsideCoroutine { expr } => {
1137                YieldOutsideCoroutine { expr: expr_syntax(expr)? }.into()
1138            }
1139            &InferenceDiagnostic::ReturnOutsideFunction { expr, kind } => {
1140                ReturnOutsideFunction { expr: expr_syntax(expr)?, kind }.into()
1141            }
1142            &InferenceDiagnostic::RecordMissingFields { record, variant, ref missed_fields } => {
1143                let record = expr_or_pat_syntax(record)?;
1144                let file = record.file_id;
1145                let root = record.file_syntax(db);
1146                let variant_data = variant.fields(db);
1147                let missed_fields = missed_fields
1148                    .iter()
1149                    .map(|&idx| {
1150                        (
1151                            variant_data.fields()[idx].name.clone(),
1152                            Field { parent: variant.into(), id: idx },
1153                        )
1154                    })
1155                    .collect();
1156                match record.value.to_node(&root) {
1157                    Either::Left(ast::Expr::RecordExpr(record_expr))
1158                        if record_expr.record_expr_field_list().is_some() =>
1159                    {
1160                        let field_list_parent_path =
1161                            record_expr.path().map(|path| AstPtr::new(&path));
1162                        return Some(
1163                            MissingFields {
1164                                file,
1165                                field_list_parent: AstPtr::new(&Either::Left(record_expr)),
1166                                field_list_parent_path,
1167                                missed_fields,
1168                            }
1169                            .into(),
1170                        );
1171                    }
1172                    Either::Right(ast::Pat::RecordPat(record_pat))
1173                        if record_pat.record_pat_field_list().is_some() =>
1174                    {
1175                        let field_list_parent_path =
1176                            record_pat.path().map(|path| AstPtr::new(&path));
1177                        MissingFields {
1178                            file,
1179                            field_list_parent: AstPtr::new(&Either::Right(record_pat)),
1180                            field_list_parent_path,
1181                            missed_fields,
1182                        }
1183                        .into()
1184                    }
1185                    _ => return None,
1186                }
1187            }
1188        })
1189    }
1190
1191    fn solver_diagnostic(
1192        db: &'db dyn HirDatabase,
1193        d: &'db SolverDiagnosticKind,
1194        span: SpanSyntax,
1195        type_owner: TypeOwnerId<'db>,
1196    ) -> Option<AnyDiagnostic<'db>> {
1197        let interner = DbInterner::new_no_crate(db);
1198        Some(match d {
1199            SolverDiagnosticKind::TraitUnimplemented {
1200                trait_predicate,
1201                parent_trait_predicates,
1202            } => {
1203                let trait_predicate = crate::TraitPredicate {
1204                    inner: trait_predicate.get(interner),
1205                    owner: type_owner,
1206                };
1207                let parent_trait_predicates = parent_trait_predicates
1208                    .iter()
1209                    .map(|trait_predicate| crate::TraitPredicate {
1210                        inner: trait_predicate.get(interner),
1211                        owner: type_owner,
1212                    })
1213                    .collect();
1214                UnimplementedTrait { span, trait_predicate, parent_trait_predicates }.into()
1215            }
1216        })
1217    }
1218
1219    fn path_diagnostic(
1220        diag: &PathLoweringDiagnostic,
1221        path: InFile<ast::Path>,
1222    ) -> Option<AnyDiagnostic<'db>> {
1223        Some(match *diag {
1224            PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
1225                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
1226
1227                if let Some(rtn) = segment.return_type_syntax() {
1228                    // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
1229                    return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
1230                }
1231
1232                let args = if let Some(generics) = segment.generic_arg_list() {
1233                    AstPtr::new(&generics).wrap_left()
1234                } else {
1235                    AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
1236                };
1237                let args = path.with_value(args);
1238                GenericArgsProhibited { args, reason }.into()
1239            }
1240            PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment } => {
1241                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
1242
1243                if let Some(rtn) = segment.return_type_syntax() {
1244                    // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
1245                    return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
1246                }
1247
1248                let args = AstPtr::new(&segment.parenthesized_arg_list()?);
1249                let args = path.with_value(args);
1250                ParenthesizedGenericArgsWithoutFnTrait { args }.into()
1251            }
1252            PathLoweringDiagnostic::IncorrectGenericsLen {
1253                generics_source,
1254                provided_count,
1255                expected_count,
1256                kind,
1257                def,
1258            } => {
1259                let generics_or_segment =
1260                    path_generics_source_to_ast(&path.value, generics_source)?;
1261                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
1262                IncorrectGenericsLen {
1263                    generics_or_segment,
1264                    kind,
1265                    provided: provided_count,
1266                    expected: expected_count,
1267                    def: def.into(),
1268                }
1269                .into()
1270            }
1271            PathLoweringDiagnostic::IncorrectGenericsOrder {
1272                generics_source,
1273                param_id,
1274                arg_idx,
1275                has_self_arg,
1276            } => {
1277                let generic_args =
1278                    path_generics_source_to_ast(&path.value, generics_source)?.left()?;
1279                let provided_arg = hir_generic_arg_to_ast(&generic_args, arg_idx, has_self_arg)?;
1280                let provided_arg = path.with_value(AstPtr::new(&provided_arg));
1281                let expected_kind = GenericArgKind::from_id(param_id);
1282                IncorrectGenericsOrder { provided_arg, expected_kind }.into()
1283            }
1284            PathLoweringDiagnostic::MissingLifetime { generics_source, expected_count, def }
1285            | PathLoweringDiagnostic::ElisionFailure { generics_source, expected_count, def } => {
1286                let generics_or_segment =
1287                    path_generics_source_to_ast(&path.value, generics_source)?;
1288                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
1289                MissingLifetime { generics_or_segment, expected: expected_count, def: def.into() }
1290                    .into()
1291            }
1292            PathLoweringDiagnostic::ElidedLifetimesInPath {
1293                generics_source,
1294                expected_count,
1295                def,
1296                hard_error,
1297            } => {
1298                let generics_or_segment =
1299                    path_generics_source_to_ast(&path.value, generics_source)?;
1300                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
1301                ElidedLifetimesInPath {
1302                    generics_or_segment,
1303                    expected: expected_count,
1304                    def: def.into(),
1305                    hard_error,
1306                }
1307                .into()
1308            }
1309            PathLoweringDiagnostic::GenericDefaultRefersToSelf { segment } => {
1310                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
1311                let segment = path.with_value(AstPtr::new(&segment));
1312                GenericDefaultRefersToSelf { segment }.into()
1313            }
1314        })
1315    }
1316
1317    fn expr_syntax(
1318        expr: ExprId,
1319        source_map: &ExpressionStoreSourceMap,
1320    ) -> Option<InFile<ExprOrPatPtr>> {
1321        source_map
1322            .expr_syntax(expr)
1323            .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr"))
1324            .ok()
1325    }
1326
1327    fn pat_syntax(
1328        pat: PatId,
1329        source_map: &ExpressionStoreSourceMap,
1330    ) -> Option<InFile<ExprOrPatPtr>> {
1331        source_map
1332            .pat_syntax(pat)
1333            .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern"))
1334            .ok()
1335    }
1336
1337    fn type_syntax(
1338        type_ref: TypeRefId,
1339        source_map: &ExpressionStoreSourceMap,
1340    ) -> Option<InFile<AstPtr<ast::Type>>> {
1341        source_map
1342            .type_syntax(type_ref)
1343            .inspect_err(|_| stdx::never!("inference diagnostic in desugared type"))
1344            .ok()
1345    }
1346
1347    fn span_syntax(
1348        span: hir_ty::Span,
1349        source_map: &ExpressionStoreSourceMap,
1350    ) -> Option<InFile<AstPtr<SpanAst>>> {
1351        Some(match span {
1352            hir_ty::Span::ExprId(idx) => Self::expr_syntax(idx, source_map)?.map(|it| it.upcast()),
1353            hir_ty::Span::PatId(idx) => Self::pat_syntax(idx, source_map)?.map(|it| it.upcast()),
1354            hir_ty::Span::TypeRefId(idx) => {
1355                Self::type_syntax(idx, source_map)?.map(|it| it.upcast())
1356            }
1357            hir_ty::Span::BindingId(idx) => {
1358                let &pat = source_map.patterns_for_binding(idx).first()?;
1359                Self::pat_syntax(pat, source_map)?.map(|it| it.upcast())
1360            }
1361            hir_ty::Span::Dummy => {
1362                never!("should never create a diagnostic for dummy spans");
1363                return None;
1364            }
1365        })
1366    }
1367
1368    pub(crate) fn ty_diagnostic(
1369        diag: &TyLoweringDiagnostic,
1370        source_map: &ExpressionStoreSourceMap,
1371        db: &'db dyn HirDatabase,
1372    ) -> Option<AnyDiagnostic<'db>> {
1373        Some(match diag {
1374            TyLoweringDiagnostic::PathDiagnostic { source, diag } => {
1375                let source = Self::type_syntax(*source, source_map)?;
1376                let syntax = source.value.to_node(&source.file_id.parse_or_expand(db));
1377                let ast::Type::PathType(syntax) = syntax else { return None };
1378                Self::path_diagnostic(diag, source.with_value(syntax.path()?))?
1379            }
1380            TyLoweringDiagnostic::InferVarsNotAllowed { source } => {
1381                let source = Self::span_syntax(*source, source_map)?;
1382                InferVarsNotAllowed { node: source.map(Into::into) }.into()
1383            }
1384        })
1385    }
1386}
1387
1388fn path_generics_source_to_ast(
1389    path: &ast::Path,
1390    generics_source: PathGenericsSource,
1391) -> Option<Either<ast::GenericArgList, ast::NameRef>> {
1392    Some(match generics_source {
1393        PathGenericsSource::Segment(segment) => {
1394            let segment = hir_segment_to_ast_segment(path, segment)?;
1395            segment
1396                .generic_arg_list()
1397                .map(Either::Left)
1398                .or_else(|| segment.name_ref().map(Either::Right))?
1399        }
1400        PathGenericsSource::AssocType { segment, assoc_type } => {
1401            let segment = hir_segment_to_ast_segment(path, segment)?;
1402            let segment_args = segment.generic_arg_list()?;
1403            let assoc = hir_assoc_type_binding_to_ast(&segment_args, assoc_type)?;
1404            assoc
1405                .generic_arg_list()
1406                .map(Either::Left)
1407                .or_else(|| assoc.name_ref().map(Either::Right))?
1408        }
1409    })
1410}