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