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