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