1use 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 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#[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 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 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 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 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 && 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 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 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 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 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}