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