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