Skip to main content

hir/
diagnostics.rs

1//! Re-export diagnostics such that clients of `hir` don't have to depend on
2//! low-level crates.
3//!
4//! This probably isn't the best way to do this -- ideally, diagnostics should
5//! be expressed in terms of hir types themselves.
6use std::mem::discriminant;
7
8use cfg::{CfgExpr, CfgOptions};
9use either::Either;
10use hir_def::{
11    AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, GenericDefId, GenericParamId, ImplId,
12    Lookup, MacroId, ModuleDefId, ModuleId, SyntheticSyntax, TraitId,
13    attrs::AttrFlags,
14    expr_store::{
15        Body, ExprOrPatPtr, ExpressionStore, ExpressionStoreDiagnostics, ExpressionStoreSourceMap,
16        hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment,
17    },
18    hir::{ExprId, ExprOrPatId, PatId},
19    nameres::{
20        DefMap,
21        assoc::{ImplItems, TraitItems},
22        diagnostics::{DefDiagnosticKind, DefDiagnostics},
23    },
24    resolver::ValueNs,
25    signatures::{
26        ConstSignature, FunctionSignature, ImplFlags, ImplSignature, TraitFlags, TraitSignature,
27        TypeAliasSignature,
28    },
29    type_ref::TypeRefId,
30    unstable_features::UnstableFeatures,
31};
32use hir_expand::{
33    HirFileId, InFile, MacroCallId, MacroCallKind, MacroKind, RenderedExpandError, ValueResult,
34    mod_path::ModPath, name::Name,
35};
36use hir_ide::{
37    CastError, ExplicitDropMethodUseKind, InferBodyId, InferenceDiagnostic, InferenceResult,
38    ParamEnvAndCrate, PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic,
39    check_orphan_rules,
40    db::{AnonConstId, HirDatabase, signature_anon_consts_and_diagnostics},
41    diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
42    display::{DisplayTarget, HirDisplay},
43    method_resolution::TraitImpls,
44    next_solver::{
45        DbInterner, EarlyBinder, TyKind, TypingMode,
46        infer::{DbInternerInferExt, InferCtxt},
47    },
48    solver_errors::SolverDiagnosticKind,
49    traits::{is_inherent_impl_coherent, structurally_normalize_ty},
50};
51use rustc_type_ir::inherent::IntoKind as _;
52use span::Edition;
53use stdx::{impl_from, never};
54use syntax::{
55    AstNode, AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
56    ast::{self, HasGenericArgs, HasName},
57    match_ast,
58};
59use triomphe::Arc;
60
61use crate::{
62    AnyFunctionId, AssocItem, Field, Function, GenericDef, Trait, Type, TypeOwnerId, Variant,
63    struct_tail_raw,
64};
65
66pub use hir_def::{VariantId, expr_store::MissingBodyItemKind};
67pub use hir_ide::{
68    GenericArgsProhibitedReason, IncorrectGenericsLenKind, ReturnKind,
69    diagnostics::{CaseType, IncorrectCase},
70};
71
72#[derive(Debug, Clone)]
73pub enum SpanAst {
74    Expr(ast::Expr),
75    Pat(ast::Pat),
76    Type(ast::Type),
77}
78const _: () = {
79    use syntax::ast::*;
80    impl_from!(Expr, Pat, Type for SpanAst);
81};
82
83impl From<Either<ast::Expr, ast::Pat>> for SpanAst {
84    fn from(value: Either<ast::Expr, ast::Pat>) -> Self {
85        match value {
86            Either::Left(it) => it.into(),
87            Either::Right(it) => it.into(),
88        }
89    }
90}
91
92impl ast::AstNode for SpanAst {
93    fn can_cast(kind: syntax::SyntaxKind) -> bool {
94        ast::Expr::can_cast(kind) || ast::Pat::can_cast(kind) || ast::Type::can_cast(kind)
95    }
96
97    fn cast(syntax: syntax::SyntaxNode) -> Option<Self> {
98        ast::Expr::cast(syntax.clone())
99            .map(SpanAst::Expr)
100            .or_else(|| ast::Pat::cast(syntax.clone()).map(SpanAst::Pat))
101            .or_else(|| ast::Type::cast(syntax).map(SpanAst::Type))
102    }
103
104    fn syntax(&self) -> &syntax::SyntaxNode {
105        match self {
106            SpanAst::Expr(it) => it.syntax(),
107            SpanAst::Pat(it) => it.syntax(),
108            SpanAst::Type(it) => it.syntax(),
109        }
110    }
111}
112
113pub type SpanSyntax = InFile<AstPtr<SpanAst>>;
114
115macro_rules! diagnostics {
116    ($AnyDiagnostic:ident <$db:lifetime> -> $($diag:ident $(<$lt:lifetime>)?,)*) => {
117        #[derive(Debug)]
118        pub enum $AnyDiagnostic<$db> {$(
119            $diag(Box<$diag $(<$lt>)?>),
120        )*}
121
122        $(
123            impl<$db> From<$diag $(<$lt>)?> for $AnyDiagnostic<$db> {
124                fn from(d: $diag $(<$lt>)?) -> $AnyDiagnostic<$db> {
125                    $AnyDiagnostic::$diag(Box::new(d))
126                }
127            }
128        )*
129    };
130}
131
132diagnostics![AnyDiagnostic<'db> ->
133    ArrayPatternWithoutFixedLength,
134    AwaitOutsideOfAsync,
135    BreakOutsideOfLoop,
136    CannotBeDereferenced<'db>,
137    UnaryOperatorCannotBeApplied<'db>,
138    CannotImplicitlyDerefTraitObject<'db>,
139    CannotIndexInto<'db>,
140    CastToUnsized<'db>,
141    ExpectedArrayOrSlicePat<'db>,
142    ExpectedFunction<'db>,
143    ExplicitDropMethodUse,
144    FruInDestructuringAssignment,
145    MissingBody,
146    FunctionalRecordUpdateOnNonStruct,
147    GenericDefaultRefersToSelf,
148    InactiveCode,
149    IncoherentImpl,
150    IncorrectCase,
151    IncorrectGenericsLen,
152    IncorrectGenericsOrder,
153    InferVarsNotAllowed,
154    InvalidCast<'db>,
155    InvalidDeriveTarget,
156    InvalidLhsOfAssignment,
157    InvalidRangePatType,
158    InvalidPatPathRes,
159    MacroDefError,
160    MacroError,
161    MacroExpansionParseError,
162    MalformedDerive,
163    MethodCallIllegalSizedBound,
164    MismatchedArgCount,
165    MismatchedTupleStructPatArgCount,
166    MissingFields,
167    MissingMatchArms,
168    MissingUnsafe,
169    MutRefInImmRefPat,
170    MutableRefBinding,
171    NonExhaustiveLet,
172    NonExhaustiveRecordExpr,
173    NonExhaustiveRecordPat,
174    NoSuchField,
175    MismatchedArrayPatLen,
176    DuplicateField,
177    PatternArgInExternFn,
178    PrivateAssocItem,
179    PrivateField,
180    RemoveTrailingReturn,
181    RemoveUnnecessaryElse,
182    UnusedMustUse<'db>,
183    ReplaceFilterMapNextWithFindMap,
184    TraitImplIncorrectSafety,
185    TraitImplMissingAssocItems,
186    TraitImplOrphan,
187    TraitImplRedundantAssocItems,
188    TypedHole<'db>,
189    TypeMismatch<'db>,
190    UndeclaredLabel,
191    UnimplementedBuiltinMacro,
192    UnreachableLabel,
193    UnresolvedAssocItem,
194    UnresolvedExternCrate,
195    UnresolvedField<'db>,
196    UnresolvedImport,
197    UnresolvedMacroCall,
198    UnresolvedMethodCall<'db>,
199    UnresolvedModule,
200    UnresolvedIdent,
201    GenericArgsProhibited,
202    ParenthesizedGenericArgsWithoutFnTrait,
203    BadRtn,
204    MissingLifetime,
205    ElidedLifetimesInPath,
206    TypeMustBeKnown<'db>,
207    UnionExprMustHaveExactlyOneField,
208    UnionPatMustHaveExactlyOneField,
209    UnionPatHasRest,
210    UnimplementedTrait<'db>,
211    YieldOutsideCoroutine,
212    ReturnOutsideFunction,
213    MatchInheritedImmRefWithMutRefPat,
214    UnresolvedAssociatedType,
215];
216
217#[derive(Debug)]
218pub struct BreakOutsideOfLoop {
219    pub expr: InFile<ExprOrPatPtr>,
220    pub is_break: bool,
221    pub bad_value_break: bool,
222}
223
224#[derive(Debug)]
225pub struct TypedHole<'db> {
226    pub expr: InFile<ExprOrPatPtr>,
227    pub expected: Type<'db>,
228}
229
230#[derive(Debug)]
231pub struct UnresolvedModule {
232    pub decl: InFile<AstPtr<ast::Module>>,
233    pub candidates: Box<[String]>,
234}
235
236#[derive(Debug)]
237pub struct UnresolvedExternCrate {
238    pub decl: InFile<AstPtr<ast::ExternCrate>>,
239}
240
241#[derive(Debug)]
242pub struct UnresolvedImport {
243    pub decl: InFile<AstPtr<ast::UseTree>>,
244}
245
246#[derive(Debug, Clone, Eq, PartialEq)]
247pub struct UnresolvedMacroCall {
248    pub range: InFile<TextRange>,
249    pub path: ModPath,
250    pub is_bang: bool,
251}
252#[derive(Debug, Clone, Eq, PartialEq)]
253pub struct UnreachableLabel {
254    pub node: InFile<AstPtr<ast::Lifetime>>,
255    pub name: Name,
256}
257
258#[derive(Debug)]
259pub struct AwaitOutsideOfAsync {
260    pub node: InFile<AstPtr<ast::AwaitExpr>>,
261    pub location: String,
262}
263
264#[derive(Debug, Clone, Eq, PartialEq)]
265pub struct UndeclaredLabel {
266    pub node: InFile<AstPtr<ast::Lifetime>>,
267    pub name: Name,
268}
269
270#[derive(Debug, Clone, Eq, PartialEq)]
271pub struct InactiveCode {
272    pub node: InFile<SyntaxNodePtr>,
273    pub cfg: CfgExpr,
274    pub opts: CfgOptions,
275}
276
277#[derive(Debug, Clone, Eq, PartialEq)]
278pub struct MacroError {
279    pub range: InFile<TextRange>,
280    pub message: String,
281    pub error: bool,
282    pub kind: &'static str,
283}
284
285#[derive(Debug, Clone, Eq, PartialEq)]
286pub struct MacroExpansionParseError {
287    pub range: InFile<TextRange>,
288    pub errors: Arc<[SyntaxError]>,
289}
290
291#[derive(Debug, Clone, Eq, PartialEq)]
292pub struct MacroDefError {
293    pub node: InFile<AstPtr<ast::Macro>>,
294    pub message: String,
295    pub name: Option<TextRange>,
296}
297
298#[derive(Debug)]
299pub struct UnimplementedBuiltinMacro {
300    pub node: InFile<SyntaxNodePtr>,
301}
302
303#[derive(Debug)]
304pub struct InvalidDeriveTarget {
305    pub range: InFile<TextRange>,
306}
307
308#[derive(Debug)]
309pub struct MalformedDerive {
310    pub range: InFile<TextRange>,
311}
312
313#[derive(Debug)]
314pub struct NoSuchField {
315    pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
316    pub private: Option<Field>,
317    pub variant: VariantId,
318}
319
320#[derive(Debug)]
321pub struct DuplicateField {
322    pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
323    pub variant: Variant,
324}
325
326#[derive(Debug)]
327pub struct PrivateAssocItem {
328    pub expr_or_pat: InFile<ExprOrPatPtr>,
329    pub item: AssocItem,
330}
331
332#[derive(Debug)]
333pub struct MismatchedTupleStructPatArgCount {
334    pub expr_or_pat: InFile<ExprOrPatPtr>,
335    pub expected: usize,
336    pub found: usize,
337}
338
339#[derive(Debug)]
340pub struct MismatchedArrayPatLen {
341    pub pat: InFile<ExprOrPatPtr>,
342    pub expected: u64,
343    pub found: u64,
344    pub has_rest: bool,
345}
346
347#[derive(Debug)]
348pub struct ArrayPatternWithoutFixedLength {
349    pub pat: InFile<ExprOrPatPtr>,
350}
351
352#[derive(Debug)]
353pub struct ExpectedArrayOrSlicePat<'db> {
354    pub pat: InFile<ExprOrPatPtr>,
355    pub found: Type<'db>,
356}
357
358#[derive(Debug)]
359pub struct InvalidRangePatType {
360    pub pat: InFile<ExprOrPatPtr>,
361}
362
363#[derive(Debug)]
364pub struct ExpectedFunction<'db> {
365    pub call: InFile<ExprOrPatPtr>,
366    pub found: Type<'db>,
367}
368
369#[derive(Debug)]
370pub struct CannotBeDereferenced<'db> {
371    pub expr: InFile<ExprOrPatPtr>,
372    pub found: Type<'db>,
373}
374
375#[derive(Debug)]
376pub struct UnaryOperatorCannotBeApplied<'db> {
377    pub expr: InFile<ExprOrPatPtr>,
378    pub op: ast::UnaryOp,
379    pub found: Type<'db>,
380}
381
382#[derive(Debug)]
383pub struct MutRefInImmRefPat {
384    pub pat: InFile<ExprOrPatPtr>,
385}
386
387#[derive(Debug)]
388pub struct CannotImplicitlyDerefTraitObject<'db> {
389    pub pat: InFile<ExprOrPatPtr>,
390    pub found: Type<'db>,
391}
392
393#[derive(Debug)]
394pub struct CannotIndexInto<'db> {
395    pub expr: InFile<ExprOrPatPtr>,
396    pub found: Type<'db>,
397}
398
399#[derive(Debug)]
400pub struct ExplicitDropMethodUse {
401    pub expr_or_path: Either<InFile<AstPtr<ast::MethodCallExpr>>, InFile<AstPtr<ast::Path>>>,
402}
403
404#[derive(Debug)]
405pub struct FruInDestructuringAssignment {
406    pub node: InFile<AstPtr<ast::Expr>>,
407}
408
409#[derive(Debug)]
410pub struct MissingBody {
411    pub node: InFile<SyntaxNodePtr>,
412    pub kind: MissingBodyItemKind,
413}
414
415#[derive(Debug)]
416pub struct FunctionalRecordUpdateOnNonStruct {
417    pub base_expr: InFile<ExprOrPatPtr>,
418}
419
420#[derive(Debug)]
421pub struct UnresolvedField<'db> {
422    pub expr: InFile<ExprOrPatPtr>,
423    pub receiver: Type<'db>,
424    pub name: Name,
425    pub method_with_same_name_exists: bool,
426}
427
428#[derive(Debug)]
429pub struct UnresolvedMethodCall<'db> {
430    pub expr: InFile<ExprOrPatPtr>,
431    pub receiver: Type<'db>,
432    pub name: Name,
433    pub field_with_same_name: Option<Type<'db>>,
434    pub assoc_func_with_same_name: Option<Function>,
435}
436
437#[derive(Debug)]
438pub struct UnresolvedAssocItem {
439    pub expr_or_pat: InFile<ExprOrPatPtr>,
440}
441
442#[derive(Debug)]
443pub struct UnresolvedIdent {
444    pub node: InFile<(ExprOrPatPtr, Option<TextRange>)>,
445}
446
447#[derive(Debug)]
448pub struct PrivateField {
449    pub expr: InFile<ExprOrPatPtr>,
450    pub field: Field,
451}
452
453#[derive(Debug, Clone, Copy, PartialEq, Eq)]
454pub enum UnsafeLint {
455    HardError,
456    UnsafeOpInUnsafeFn,
457    DeprecatedSafe2024,
458}
459
460#[derive(Debug)]
461pub struct MissingUnsafe {
462    pub node: InFile<ExprOrPatPtr>,
463    pub lint: UnsafeLint,
464    pub reason: UnsafetyReason,
465}
466
467#[derive(Debug)]
468pub struct MissingFields {
469    pub file: HirFileId,
470    pub field_list_parent: AstPtr<Either<ast::RecordExpr, ast::RecordPat>>,
471    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
472    pub missed_fields: Vec<(Name, Field)>,
473}
474
475#[derive(Debug)]
476pub struct ReplaceFilterMapNextWithFindMap {
477    pub file: HirFileId,
478    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
479    pub next_expr: AstPtr<ast::Expr>,
480}
481
482#[derive(Debug)]
483pub struct MismatchedArgCount {
484    pub call_expr: InFile<ExprOrPatPtr>,
485    pub expected: usize,
486    pub found: usize,
487    /// True when the call is through a `Fn`/`FnMut`/`FnOnce` trait (E0057)
488    /// rather than a regular function call (E0061).
489    pub is_fn_trait_call: bool,
490}
491
492#[derive(Debug)]
493pub struct MissingMatchArms {
494    pub scrutinee_expr: InFile<AstPtr<ast::Expr>>,
495    pub uncovered_patterns: String,
496}
497
498#[derive(Debug)]
499pub struct NonExhaustiveLet {
500    pub pat: InFile<AstPtr<ast::Pat>>,
501    pub uncovered_patterns: String,
502}
503
504#[derive(Debug)]
505pub struct NonExhaustiveRecordExpr {
506    pub expr: InFile<ExprOrPatPtr>,
507}
508
509#[derive(Debug)]
510pub struct NonExhaustiveRecordPat {
511    pub pat: InFile<ExprOrPatPtr>,
512    pub variant: Variant,
513}
514
515#[derive(Debug)]
516pub struct TypeMismatch<'db> {
517    pub expr_or_pat: InFile<ExprOrPatPtr>,
518    pub expected: Type<'db>,
519    pub actual: Type<'db>,
520}
521
522#[derive(Debug, PartialEq, Eq)]
523pub struct IncoherentImpl {
524    pub file_id: HirFileId,
525    pub impl_: AstPtr<ast::Impl>,
526}
527
528#[derive(Debug, PartialEq, Eq)]
529pub struct TraitImplOrphan {
530    pub file_id: HirFileId,
531    pub impl_: AstPtr<ast::Impl>,
532}
533
534// FIXME: Split this off into the corresponding 4 rustc errors
535#[derive(Debug, PartialEq, Eq)]
536pub struct TraitImplIncorrectSafety {
537    pub file_id: HirFileId,
538    pub impl_: AstPtr<ast::Impl>,
539    pub should_be_safe: bool,
540}
541
542#[derive(Debug, PartialEq, Eq)]
543pub struct TraitImplMissingAssocItems {
544    pub file_id: HirFileId,
545    pub impl_: AstPtr<ast::Impl>,
546    pub missing: Vec<(Name, AssocItem)>,
547}
548
549#[derive(Debug, PartialEq, Eq)]
550pub struct TraitImplRedundantAssocItems {
551    pub file_id: HirFileId,
552    pub trait_: Trait,
553    pub impl_: AstPtr<ast::Impl>,
554    pub assoc_item: (Name, AssocItem),
555}
556
557#[derive(Debug)]
558pub struct RemoveTrailingReturn {
559    pub return_expr: InFile<AstPtr<ast::ReturnExpr>>,
560}
561
562#[derive(Debug)]
563pub struct RemoveUnnecessaryElse {
564    pub if_expr: InFile<AstPtr<ast::IfExpr>>,
565}
566
567#[derive(Debug)]
568pub struct UnusedMustUse<'db> {
569    pub expr: InFile<ExprOrPatPtr>,
570    pub message: Option<&'db str>,
571}
572
573#[derive(Debug)]
574pub struct CastToUnsized<'db> {
575    pub expr: InFile<ExprOrPatPtr>,
576    pub cast_ty: Type<'db>,
577}
578
579#[derive(Debug)]
580pub struct InvalidCast<'db> {
581    pub expr: InFile<ExprOrPatPtr>,
582    pub error: CastError,
583    pub expr_ty: Type<'db>,
584    pub cast_ty: Type<'db>,
585}
586
587#[derive(Debug)]
588pub struct GenericArgsProhibited {
589    pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>,
590    pub reason: GenericArgsProhibitedReason,
591}
592
593#[derive(Debug)]
594pub struct ParenthesizedGenericArgsWithoutFnTrait {
595    pub args: InFile<AstPtr<ast::ParenthesizedArgList>>,
596}
597
598#[derive(Debug)]
599pub struct BadRtn {
600    pub rtn: InFile<AstPtr<ast::ReturnTypeSyntax>>,
601}
602
603#[derive(Debug)]
604pub struct InferVarsNotAllowed {
605    pub node: InFile<SyntaxNodePtr>,
606}
607
608#[derive(Debug)]
609pub struct IncorrectGenericsLen {
610    /// Points at the name if there are no generics.
611    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
612    pub kind: IncorrectGenericsLenKind,
613    pub provided: u32,
614    pub expected: u32,
615    pub def: GenericDef,
616}
617
618#[derive(Debug)]
619pub struct MissingLifetime {
620    /// Points at the name if there are no generics.
621    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
622    pub expected: u32,
623    pub def: GenericDef,
624}
625
626#[derive(Debug)]
627pub struct ElidedLifetimesInPath {
628    /// Points at the name if there are no generics.
629    pub generics_or_segment: InFile<AstPtr<Either<ast::GenericArgList, ast::NameRef>>>,
630    pub expected: u32,
631    pub def: GenericDef,
632    pub hard_error: bool,
633}
634
635#[derive(Debug)]
636pub struct TypeMustBeKnown<'db> {
637    pub at_point: SpanSyntax,
638    pub top_term: Option<Either<Type<'db>, String>>,
639}
640
641#[derive(Debug, Clone, Copy, PartialEq, Eq)]
642pub enum GenericArgKind {
643    Lifetime,
644    Type,
645    Const,
646}
647
648impl GenericArgKind {
649    fn from_id(id: GenericParamId) -> Self {
650        match id {
651            GenericParamId::TypeParamId(_) => GenericArgKind::Type,
652            GenericParamId::ConstParamId(_) => GenericArgKind::Const,
653            GenericParamId::LifetimeParamId(_) => GenericArgKind::Lifetime,
654        }
655    }
656}
657
658#[derive(Debug)]
659pub struct IncorrectGenericsOrder {
660    pub provided_arg: InFile<AstPtr<ast::GenericArg>>,
661    pub expected_kind: GenericArgKind,
662}
663
664#[derive(Debug)]
665pub struct GenericDefaultRefersToSelf {
666    /// The `Self` segment.
667    pub segment: InFile<AstPtr<ast::PathSegment>>,
668}
669
670#[derive(Debug)]
671pub struct UnionExprMustHaveExactlyOneField {
672    pub expr: InFile<ExprOrPatPtr>,
673}
674
675#[derive(Debug)]
676pub struct UnionPatMustHaveExactlyOneField {
677    pub pat: InFile<ExprOrPatPtr>,
678}
679
680#[derive(Debug)]
681pub struct UnionPatHasRest {
682    pub pat: InFile<ExprOrPatPtr>,
683}
684
685#[derive(Debug)]
686pub struct InvalidLhsOfAssignment {
687    pub lhs: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
688}
689
690#[derive(Debug)]
691pub struct MethodCallIllegalSizedBound {
692    pub call_expr: InFile<ExprOrPatPtr>,
693}
694
695#[derive(Debug)]
696pub struct PatternArgInExternFn {
697    pub node: InFile<AstPtr<ast::Pat>>,
698}
699
700#[derive(Debug)]
701pub struct UnimplementedTrait<'db> {
702    pub span: SpanSyntax,
703    pub trait_predicate: crate::TraitPredicate<'db>,
704    pub parent_trait_predicates: Vec<crate::TraitPredicate<'db>>,
705}
706
707#[derive(Debug)]
708pub struct MutableRefBinding {
709    pub pat: InFile<ExprOrPatPtr>,
710}
711
712#[derive(Debug)]
713pub struct YieldOutsideCoroutine {
714    pub expr: InFile<ExprOrPatPtr>,
715}
716
717#[derive(Debug)]
718pub struct ReturnOutsideFunction {
719    pub expr: InFile<ExprOrPatPtr>,
720    pub kind: ReturnKind,
721}
722
723#[derive(Debug)]
724pub struct MatchInheritedImmRefWithMutRefPat {
725    pub pat: InFile<ExprOrPatPtr>,
726}
727
728#[derive(Debug, Clone, Copy, PartialEq, Eq)]
729pub enum InvalidPatPathResKind {
730    Function,
731    GenericParam,
732    ImplSelf,
733    LocalBinding,
734    Static,
735}
736
737#[derive(Debug)]
738pub struct InvalidPatPathRes {
739    pub pat: InFile<ExprOrPatPtr>,
740    pub kind: InvalidPatPathResKind,
741}
742
743#[derive(Debug)]
744pub struct UnresolvedAssociatedType {
745    pub segment: InFile<AstPtr<ast::PathSegment>>,
746}
747
748pub(crate) struct DiagnosticsCollector<'a, 'db> {
749    db: &'db dyn HirDatabase,
750    krate: base_db::Crate,
751    edition: Edition,
752    style_lints: bool,
753    acc: &'a mut Vec<AnyDiagnostic<'db>>,
754}
755
756fn precise_macro_call_location(
757    ast: &MacroCallKind,
758    db: &dyn HirDatabase,
759    krate: base_db::Crate,
760) -> InFile<TextRange> {
761    // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics
762    // - e.g. the full attribute for macro errors, but only the name for name resolution
763    match ast {
764        MacroCallKind::FnLike { ast_id, .. } => {
765            let node = ast_id.to_node(db);
766            let range = node
767                .path()
768                .and_then(|it| it.segment())
769                .and_then(|it| it.name_ref())
770                .map(|it| it.syntax().text_range());
771            let range = range.unwrap_or_else(|| node.syntax().text_range());
772            ast_id.with_value(range)
773        }
774        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
775            let range = derive_attr_index.find_derive_range(db, krate, *ast_id, *derive_index);
776            ast_id.with_value(range)
777        }
778        MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
779            let attr_range =
780                attr_ids.invoc_attr().find_attr_range(db, krate, *ast_id).1.syntax().text_range();
781            ast_id.with_value(attr_range)
782        }
783    }
784}
785
786impl<'a, 'db> DiagnosticsCollector<'a, 'db> {
787    pub(crate) fn collect(
788        db: &'db dyn HirDatabase,
789        module: ModuleId,
790        acc: &'a mut Vec<AnyDiagnostic<'db>>,
791        style_lints: bool,
792    ) {
793        let krate = module.krate(db);
794        DiagnosticsCollector { db, krate, edition: krate.data(db).edition, style_lints, acc }
795            .collect_module(module);
796    }
797
798    fn emit_def_diagnostic(&mut self, diag: &DefDiagnosticKind) {
799        match diag {
800            DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
801                let decl = declaration.to_ptr(self.db);
802                self.acc.push(
803                    UnresolvedModule {
804                        decl: InFile::new(declaration.file_id, decl),
805                        candidates: candidates.clone(),
806                    }
807                    .into(),
808                )
809            }
810            DefDiagnosticKind::UnresolvedExternCrate { ast } => {
811                let item = ast.to_ptr(self.db);
812                self.acc
813                    .push(UnresolvedExternCrate { decl: InFile::new(ast.file_id, item) }.into());
814            }
815
816            DefDiagnosticKind::MacroError { ast, path, err } => {
817                let item = ast.to_ptr(self.db);
818                let RenderedExpandError { message, error, kind } = err.render_to_string(self.db);
819                self.acc.push(
820                    MacroError {
821                        range: InFile::new(ast.file_id, item.text_range()),
822                        message: format!("{}: {message}", path.display(self.db, self.edition)),
823                        error,
824                        kind,
825                    }
826                    .into(),
827                )
828            }
829            DefDiagnosticKind::UnresolvedImport { id, index } => {
830                let file_id = id.file_id;
831
832                let use_tree = hir_def::src::use_tree_to_ast(self.db, *id, *index);
833                self.acc.push(
834                    UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
835                );
836            }
837
838            DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => {
839                let ast_id_map = ast_id.file_id.ast_id_map(self.db);
840                let ptr = ast_id_map.get_erased(ast_id.value);
841                self.acc.push(
842                    InactiveCode {
843                        node: InFile::new(ast_id.file_id, ptr),
844                        cfg: cfg.clone(),
845                        opts: opts.clone(),
846                    }
847                    .into(),
848                );
849            }
850            DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
851                let location = precise_macro_call_location(ast, self.db, self.krate);
852                self.acc.push(
853                    UnresolvedMacroCall {
854                        range: location,
855                        path: path.clone(),
856                        is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
857                    }
858                    .into(),
859                );
860            }
861            DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
862                let node = ast.to_node(self.db);
863                // Must have a name, otherwise we wouldn't emit it.
864                let name = node.name().expect("unimplemented builtin macro with no name");
865                self.acc.push(
866                    UnimplementedBuiltinMacro {
867                        node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
868                    }
869                    .into(),
870                );
871            }
872            DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
873                let (_, attr) = id.find_attr_range(self.db, self.krate, *ast);
874                let derive = attr
875                    .path()
876                    .map(|path| path.syntax().text_range())
877                    .unwrap_or_else(|| attr.syntax().text_range());
878                self.acc.push(InvalidDeriveTarget { range: ast.with_value(derive) }.into());
879            }
880            DefDiagnosticKind::MalformedDerive { ast, id } => {
881                let derive = id.find_attr_range(self.db, self.krate, *ast).1.syntax().text_range();
882                self.acc.push(MalformedDerive { range: ast.with_value(derive) }.into());
883            }
884            DefDiagnosticKind::MacroDefError { ast, message } => {
885                let node = ast.to_node(self.db);
886                self.acc.push(
887                    MacroDefError {
888                        node: InFile::new(ast.file_id, AstPtr::new(&node)),
889                        name: node.name().map(|it| it.syntax().text_range()),
890                        message: message.clone(),
891                    }
892                    .into(),
893                );
894            }
895        }
896    }
897
898    fn emit_def_diagnostics(&mut self, diagnostics: &DefDiagnostics) {
899        diagnostics.iter().for_each(|diag| self.emit_def_diagnostic(&diag.kind));
900    }
901
902    fn emit_case_diagnostics(&mut self, def: ModuleDefId) {
903        self.acc
904            .extend(hir_ide::diagnostics::incorrect_case(self.db, def).into_iter().map(Into::into));
905    }
906
907    fn collect_macro_call(&mut self, macro_call_id: MacroCallId) {
908        let Some(e) = macro_call_id.parse_macro_expansion_error(self.db) else {
909            return;
910        };
911        let ValueResult { value: parse_errors, err } = e;
912        if let Some(err) = err {
913            let loc = macro_call_id.loc(self.db);
914            let file_id = loc.kind.file_id();
915            let mut range = precise_macro_call_location(&loc.kind, self.db, loc.krate);
916            let RenderedExpandError { message, error, kind } = err.render_to_string(self.db);
917            if Some(err.span().anchor.file_id)
918                == file_id.file_id().map(|it| it.span_file_id(self.db))
919            {
920                range.value = err.span().range
921                    + file_id
922                        .ast_id_map(self.db)
923                        .get_erased(err.span().anchor.ast_id)
924                        .text_range()
925                        .start();
926            }
927            self.acc.push(MacroError { range, message, error, kind }.into());
928        }
929
930        if !parse_errors.is_empty() {
931            let loc = macro_call_id.loc(self.db);
932            let range = precise_macro_call_location(&loc.kind, self.db, loc.krate);
933            self.acc.push(MacroExpansionParseError { range, errors: parse_errors.clone() }.into())
934        }
935    }
936
937    fn collect_assoc_items(&mut self, defs: &[(Name, AssocItemId)], def_map: &DefMap) {
938        for &(_, def) in defs {
939            self.collect_module_def(def.into(), def_map);
940        }
941    }
942
943    fn collect_trait(&mut self, def: TraitId, def_map: &DefMap) {
944        let (signature, source_map) = TraitSignature::with_source_map(self.db, def);
945        let items = TraitItems::query_with_diagnostics(self.db, def);
946
947        self.collect_generic_def(&signature.store, source_map, def.into());
948        self.emit_def_diagnostics(&items.1);
949        items.0.macro_calls().for_each(|(_, call)| self.collect_macro_call(call));
950        self.collect_assoc_items(&items.0.items, def_map);
951    }
952
953    fn collect_impl(
954        &mut self,
955        def: ImplId,
956        infcx: &InferCtxt<'db>,
957        def_map: &'db DefMap,
958        impl_assoc_items_scratch: &mut Vec<(Name, AssocItemId)>,
959    ) {
960        let (impl_signature, source_map) = ImplSignature::with_source_map(self.db, def);
961        let impl_items = ImplItems::of(self.db, def);
962
963        self.collect_generic_def(&impl_signature.store, source_map, def.into());
964        self.emit_def_diagnostics(&impl_items.1);
965        impl_items.0.macro_calls().for_each(|(_, call)| self.collect_macro_call(call));
966        self.collect_assoc_items(&impl_items.0.items, def_map);
967
968        let loc = def.lookup(self.db);
969
970        let file_id = loc.id.file_id;
971        if file_id.macro_file().is_some_and(|it| it.kind(self.db) == MacroKind::DeriveBuiltIn) {
972            // these expansion come from us, diagnosing them is a waste of resources
973            // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
974            return;
975        }
976
977        let ast_id_map = file_id.ast_id_map(self.db);
978
979        let trait_impl = impl_signature.target_trait.is_some();
980        if !trait_impl && !is_inherent_impl_coherent(self.db, def_map, def) {
981            self.acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
982        }
983
984        if trait_impl && !check_orphan_rules(self.db, def) {
985            self.acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
986        }
987
988        let trait_ = trait_impl
989            .then(|| self.db.impl_trait(def))
990            .flatten()
991            .map(|trait_ref| trait_ref.instantiate_identity().skip_norm_wip().def_id.0);
992        let mut trait_is_unsafe = trait_.is_some_and(|trait_| {
993            TraitSignature::of(self.db, trait_).flags.contains(TraitFlags::UNSAFE)
994        });
995        let impl_is_negative = impl_signature.is_negative();
996        let impl_is_unsafe = impl_signature.flags.contains(ImplFlags::UNSAFE);
997
998        let trait_is_unresolved = trait_.is_none() && trait_impl;
999        if trait_is_unresolved {
1000            // Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe,
1001            // which may not be correct.
1002            trait_is_unsafe = impl_is_unsafe;
1003        }
1004
1005        let drop_maybe_dangle = (|| {
1006            let trait_ = trait_?;
1007            let drop_trait = infcx.interner.lang_items().Drop?;
1008            if drop_trait != trait_ {
1009                return None;
1010            }
1011            let parent = def.into();
1012            let (lifetimes_attrs, type_and_consts_attrs) =
1013                AttrFlags::query_generic_params(self.db, parent);
1014            let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE))
1015                || type_and_consts_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE));
1016            Some(res)
1017        })()
1018        .unwrap_or(false);
1019
1020        match (impl_is_unsafe, trait_is_unsafe, impl_is_negative, drop_maybe_dangle) {
1021                // unsafe negative impl
1022                (true, _, true, _) |
1023                // unsafe impl for safe trait
1024                (true, false, _, false) => self.acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
1025                // safe impl for unsafe trait
1026                (false, true, false, _) |
1027                // safe impl of dangling drop
1028                (false, false, _, true) => self.acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()),
1029                _ => (),
1030            };
1031
1032        // Negative impls can't have items, don't emit missing items diagnostic for them
1033        if let (false, Some(trait_)) = (impl_is_negative, trait_) {
1034            let trait_items = &trait_.trait_items(self.db).items;
1035            let required_items = trait_items.iter().filter(|&(_, assoc)| match *assoc {
1036                AssocItemId::FunctionId(it) => !FunctionSignature::of(self.db, it).has_body(),
1037                AssocItemId::ConstId(id) => !ConstSignature::of(self.db, id).has_body(),
1038                AssocItemId::TypeAliasId(it) => TypeAliasSignature::of(self.db, it).ty.is_none(),
1039            });
1040            impl_assoc_items_scratch.extend(impl_items.0.items.iter().cloned());
1041
1042            let redundant = impl_assoc_items_scratch
1043                .iter()
1044                .filter(|(name, id)| {
1045                    !trait_items.iter().any(|(impl_name, impl_item)| {
1046                        discriminant(impl_item) == discriminant(id) && impl_name == name
1047                    })
1048                })
1049                .map(|(name, item)| (name.clone(), AssocItem::from(*item)));
1050            for (name, assoc_item) in redundant {
1051                self.acc.push(
1052                    TraitImplRedundantAssocItems {
1053                        trait_: trait_.into(),
1054                        file_id,
1055                        impl_: ast_id_map.get(loc.id.value),
1056                        assoc_item: (name, assoc_item),
1057                    }
1058                    .into(),
1059                )
1060            }
1061
1062            let mut missing: Vec<_> = required_items
1063                .filter(|(name, id)| {
1064                    !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| {
1065                        discriminant(impl_item) == discriminant(id) && impl_name == name
1066                    })
1067                })
1068                .map(|(name, item)| (name.clone(), AssocItem::from(*item)))
1069                .collect();
1070
1071            if !missing.is_empty() {
1072                let env = ParamEnvAndCrate {
1073                    param_env: self.db.trait_environment(def.into()),
1074                    krate: self.krate,
1075                };
1076                let self_ty = self.db.impl_self_ty(def).instantiate_identity().skip_norm_wip();
1077                let self_ty = structurally_normalize_ty(infcx, self_ty, env.param_env);
1078                let tail_ty = struct_tail_raw(self.db, infcx.interner, self_ty, |ty| {
1079                    structurally_normalize_ty(infcx, ty, env.param_env)
1080                });
1081                let self_ty_is_guaranteed_unsized =
1082                    matches!(tail_ty.kind(), TyKind::Dynamic(..) | TyKind::Slice(..) | TyKind::Str);
1083                if self_ty_is_guaranteed_unsized {
1084                    missing.retain(|(_, assoc_item)| {
1085                            let assoc_item = match *assoc_item {
1086                                AssocItem::Function(it) => match it.id {
1087                                    AnyFunctionId::FunctionId(id) => id.into(),
1088                                    AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
1089                                        never!("should not have an `AnyFunctionId::BuiltinDeriveImplMethod` here");
1090                                        return false;
1091                                    },
1092                                },
1093                                AssocItem::Const(it) => it.id.into(),
1094                                AssocItem::TypeAlias(it) => it.id.into(),
1095                            };
1096                            !hir_ide::dyn_compatibility::generics_require_sized_self(self.db, assoc_item)
1097                        });
1098                }
1099            }
1100
1101            // HACK: When specialization is enabled in the current crate, and there exists
1102            // *any* blanket impl that provides a default implementation for the missing item,
1103            // suppress the missing associated item diagnostic.
1104            // This can lead to false negatives when the impl in question does not actually
1105            // specialize that blanket impl, but determining the exact specialization
1106            // relationship here would be significantly more expensive.
1107            if !missing.is_empty() {
1108                let features = UnstableFeatures::query(self.db, self.krate);
1109                if features.specialization || features.min_specialization {
1110                    missing.retain(|(assoc_name, assoc_item)| {
1111                        let AssocItem::Function(_) = assoc_item else {
1112                            return true;
1113                        };
1114
1115                        for &impl_ in
1116                            TraitImpls::for_crate(self.db, self.krate).blanket_impls(trait_)
1117                        {
1118                            if impl_ == def {
1119                                continue;
1120                            }
1121
1122                            for (name, item) in &impl_.impl_items(self.db).items {
1123                                let AssocItemId::FunctionId(fn_) = item else {
1124                                    continue;
1125                                };
1126                                if name != assoc_name {
1127                                    continue;
1128                                }
1129
1130                                if FunctionSignature::of(self.db, *fn_).is_default() {
1131                                    return false;
1132                                }
1133                            }
1134                        }
1135
1136                        true
1137                    });
1138                }
1139            }
1140
1141            if !missing.is_empty() {
1142                self.acc.push(
1143                    TraitImplMissingAssocItems {
1144                        impl_: ast_id_map.get(loc.id.value),
1145                        file_id,
1146                        missing,
1147                    }
1148                    .into(),
1149                )
1150            }
1151            impl_assoc_items_scratch.clear();
1152        }
1153    }
1154
1155    fn collect_module(&mut self, def: ModuleId) {
1156        let _p = tracing::info_span!("diagnostics", name = ?def.name(self.db)).entered();
1157
1158        let def_map = def.def_map(self.db);
1159        let scope = &def_map[def].scope;
1160
1161        for diag in def_map.diagnostics() {
1162            if diag.in_module != def {
1163                // FIXME: This is accidentally quadratic.
1164                continue;
1165            }
1166            self.emit_def_diagnostic(&diag.kind);
1167        }
1168
1169        if !def.is_block_module(self.db) {
1170            // These are reported by the body of block modules
1171            scope.all_macro_calls().for_each(|call| self.collect_macro_call(call));
1172        }
1173
1174        scope
1175            .declarations()
1176            .chain(scope.unnamed_consts().map(ModuleDefId::ConstId))
1177            .for_each(|def| self.collect_module_def(def, def_map));
1178
1179        scope.legacy_macros().flat_map(|(_, it)| it).for_each(|&def| {
1180            self.emit_case_diagnostics(def.into());
1181            self.collect_macro_def(def);
1182        });
1183
1184        let interner = DbInterner::new_with(self.db, self.krate);
1185        let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
1186        let mut impl_assoc_items_scratch = Vec::new();
1187        scope.impls().for_each(|def| {
1188            impl_assoc_items_scratch.clear();
1189            self.collect_impl(def, &infcx, def_map, &mut impl_assoc_items_scratch)
1190        });
1191    }
1192
1193    fn collect_macro_def(&mut self, def: MacroId) {
1194        let id = def.definition(self.db);
1195        if let hir_expand::MacroDefKind::Declarative(ast, _) = id.kind
1196            && let expander = ast.decl_macro_expander(self.db, id.krate)
1197            && let Some(e) = expander.mac.err()
1198        {
1199            self.emit_def_diagnostic(&DefDiagnosticKind::MacroDefError {
1200                ast,
1201                message: e.to_string(),
1202            });
1203        }
1204    }
1205
1206    fn collect_anon_const(&mut self, source_map: &ExpressionStoreSourceMap, def: AnonConstId<'db>) {
1207        self.emit_inference_errors(
1208            def.into(),
1209            source_map,
1210            TypeOwnerId::from_anon_const(def, self.db),
1211        );
1212    }
1213
1214    fn collect_enum(&mut self, def: EnumId) {
1215        self.collect_only_generic_def(def);
1216
1217        let variants = def.enum_variants_with_diagnostics(self.db);
1218        variants.0.variants.values().for_each(|&(def, _)| self.collect_enum_variant(def));
1219
1220        let file = def.lookup(self.db).id.file_id;
1221        let ast_id_map = file.ast_id_map(self.db);
1222        for diag in &variants.1 {
1223            self.acc.push(
1224                InactiveCode {
1225                    node: InFile::new(file, ast_id_map.get(diag.ast_id).syntax_node_ptr()),
1226                    cfg: diag.cfg.clone(),
1227                    opts: diag.opts.clone(),
1228                }
1229                .into(),
1230            );
1231        }
1232    }
1233
1234    fn collect_enum_variant(&mut self, def: EnumVariantId) {
1235        self.collect_def_with_body(
1236            def.into(),
1237            TypeOwnerId::GenericDefId(def.loc(self.db).parent.into()),
1238        );
1239        self.collect_variant(def.into());
1240    }
1241
1242    fn collect_anon_consts_and_ty_diagnostics(
1243        &mut self,
1244        source_map: &ExpressionStoreSourceMap,
1245        anon_consts: &[AnonConstId<'db>],
1246        diagnostics: &[TyLoweringDiagnostic],
1247    ) {
1248        anon_consts.iter().for_each(|&anon_const| self.collect_anon_const(source_map, anon_const));
1249
1250        diagnostics
1251            .iter()
1252            .filter_map(|diag| AnyDiagnostic::ty_diagnostic(diag, source_map, self.db))
1253            .for_each(|diag| self.acc.push(diag));
1254    }
1255
1256    fn collect_generic_def(
1257        &mut self,
1258        store: &ExpressionStore,
1259        source_map: &ExpressionStoreSourceMap,
1260        def: GenericDefId,
1261    ) {
1262        self.collect_expr_store(store, source_map);
1263        for (anon_consts, diagnostics) in signature_anon_consts_and_diagnostics(self.db, def) {
1264            self.collect_anon_consts_and_ty_diagnostics(source_map, anon_consts, diagnostics);
1265        }
1266    }
1267
1268    fn collect_def_with_body(&mut self, def: DefWithBodyId, type_owner: TypeOwnerId) {
1269        let (body, source_map) = Body::with_source_map(self.db, def);
1270
1271        self.collect_expr_store(body, source_map);
1272        self.emit_inference_errors(def.into(), source_map, type_owner);
1273
1274        // FIXME: Missing unsafe and body validation should be defined for any `InferBodyId`.
1275        let missing_unsafe = hir_ide::diagnostics::missing_unsafe(self.db, def);
1276        for (node, reason) in missing_unsafe.unsafe_exprs {
1277            match source_map.expr_or_pat_syntax(node) {
1278                Ok(node) => self.acc.push(
1279                    MissingUnsafe {
1280                        node,
1281                        lint: if missing_unsafe.fn_is_unsafe {
1282                            UnsafeLint::UnsafeOpInUnsafeFn
1283                        } else {
1284                            UnsafeLint::HardError
1285                        },
1286                        reason,
1287                    }
1288                    .into(),
1289                ),
1290                Err(SyntheticSyntax) => {
1291                    // FIXME: Here and elsewhere in this file, the `expr` was
1292                    // desugared, report or assert that this doesn't happen.
1293                }
1294            }
1295        }
1296        for node in missing_unsafe.deprecated_safe_calls {
1297            match source_map.expr_syntax(node) {
1298                Ok(node) => self.acc.push(
1299                    MissingUnsafe {
1300                        node,
1301                        lint: UnsafeLint::DeprecatedSafe2024,
1302                        reason: UnsafetyReason::UnsafeFnCall,
1303                    }
1304                    .into(),
1305                ),
1306                Err(SyntheticSyntax) => never!("synthetic DeprecatedSafe2024"),
1307            }
1308        }
1309
1310        for diagnostic in BodyValidationDiagnostic::collect(self.db, def, self.style_lints) {
1311            self.acc
1312                .extend(AnyDiagnostic::body_validation_diagnostic(self.db, diagnostic, source_map));
1313        }
1314    }
1315
1316    fn emit_inference_errors(
1317        &mut self,
1318        def: InferBodyId<'db>,
1319        source_map: &ExpressionStoreSourceMap,
1320        type_owner: TypeOwnerId,
1321    ) {
1322        let infer = InferenceResult::of(self.db, def);
1323
1324        self.acc.extend(infer.diagnostics().iter().filter_map(|diag| {
1325            AnyDiagnostic::inference_diagnostic(
1326                self.db,
1327                self.krate,
1328                self.edition,
1329                diag,
1330                source_map,
1331                type_owner,
1332            )
1333        }));
1334    }
1335
1336    fn collect_variant(&mut self, def: VariantId) {
1337        let (fields, source_map) = def.fields_with_source_map(self.db);
1338        self.collect_expr_store(&fields.store, source_map);
1339
1340        let lowering = self.db.field_types_with_diagnostics(def);
1341        self.collect_anon_consts_and_ty_diagnostics(
1342            source_map,
1343            lowering.defined_anon_consts(),
1344            lowering.diagnostics(),
1345        );
1346    }
1347
1348    fn collect_generic_def_with_body(
1349        &mut self,
1350        def: impl Into<GenericDefId> + Into<DefWithBodyId> + Copy,
1351    ) {
1352        let generic_def: GenericDefId = def.into();
1353        let (signature_store, signature_source_map) =
1354            ExpressionStore::with_source_map(self.db, generic_def.into());
1355        self.collect_generic_def(signature_store, signature_source_map, generic_def);
1356
1357        let def_with_body: DefWithBodyId = def.into();
1358        self.collect_def_with_body(def_with_body, generic_def.into());
1359    }
1360
1361    fn collect_generic_variant(&mut self, def: impl Into<GenericDefId> + Into<VariantId> + Copy) {
1362        let generic_def: GenericDefId = def.into();
1363        let (store, source_map) = ExpressionStore::with_source_map(self.db, generic_def.into());
1364        self.collect_generic_def(store, source_map, generic_def);
1365        self.collect_variant(def.into());
1366    }
1367
1368    fn collect_only_generic_def(&mut self, def: impl Into<GenericDefId>) {
1369        let generic_def: GenericDefId = def.into();
1370        let (store, source_map) = ExpressionStore::with_source_map(self.db, generic_def.into());
1371        self.collect_generic_def(store, source_map, generic_def);
1372    }
1373
1374    fn collect_module_def(&mut self, def: ModuleDefId, def_map: &DefMap) {
1375        self.emit_case_diagnostics(def);
1376
1377        match def {
1378            ModuleDefId::ModuleId(def) => {
1379                // Only add diagnostics from inline modules
1380                if def_map[def].origin.is_inline() {
1381                    self.collect_module(def);
1382                }
1383            }
1384            ModuleDefId::TraitId(def) => self.collect_trait(def, def_map),
1385            ModuleDefId::MacroId(def) => self.collect_macro_def(def),
1386            ModuleDefId::FunctionId(def) => self.collect_generic_def_with_body(def),
1387            ModuleDefId::ConstId(def) => self.collect_generic_def_with_body(def),
1388            ModuleDefId::StaticId(def) => self.collect_generic_def_with_body(def),
1389            ModuleDefId::EnumVariantId(def) => self.collect_enum_variant(def),
1390            ModuleDefId::AdtId(AdtId::StructId(def)) => self.collect_generic_variant(def),
1391            ModuleDefId::AdtId(AdtId::UnionId(def)) => self.collect_generic_variant(def),
1392            ModuleDefId::AdtId(AdtId::EnumId(def)) => self.collect_enum(def),
1393            ModuleDefId::TypeAliasId(def) => self.collect_only_generic_def(def),
1394            ModuleDefId::BuiltinType(_) => {}
1395        }
1396    }
1397
1398    fn collect_expr_store(
1399        &mut self,
1400        store: &ExpressionStore,
1401        source_map: &ExpressionStoreSourceMap,
1402    ) {
1403        for (_, def_map) in store.blocks(self.db) {
1404            self.collect_module(def_map.root_module_id());
1405        }
1406
1407        for diag in source_map.diagnostics() {
1408            self.acc.push(match diag {
1409                ExpressionStoreDiagnostics::InactiveCode { node, cfg, opts } => {
1410                    InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
1411                }
1412                ExpressionStoreDiagnostics::UnresolvedMacroCall { node, path } => {
1413                    UnresolvedMacroCall {
1414                        range: node.map(|ptr| ptr.text_range()),
1415                        path: path.clone(),
1416                        is_bang: true,
1417                    }
1418                    .into()
1419                }
1420                ExpressionStoreDiagnostics::AwaitOutsideOfAsync { node, location } => {
1421                    AwaitOutsideOfAsync { node: *node, location: location.clone() }.into()
1422                }
1423                ExpressionStoreDiagnostics::UnreachableLabel { node, name } => {
1424                    UnreachableLabel { node: *node, name: name.clone() }.into()
1425                }
1426                ExpressionStoreDiagnostics::UndeclaredLabel { node, name } => {
1427                    UndeclaredLabel { node: *node, name: name.clone() }.into()
1428                }
1429                ExpressionStoreDiagnostics::PatternArgInExternFn { node } => {
1430                    PatternArgInExternFn { node: *node }.into()
1431                }
1432                ExpressionStoreDiagnostics::FruInDestructuringAssignment { node } => {
1433                    FruInDestructuringAssignment { node: *node }.into()
1434                }
1435                ExpressionStoreDiagnostics::MissingBody { node, kind } => {
1436                    MissingBody { node: *node, kind: *kind }.into()
1437                }
1438            });
1439        }
1440
1441        source_map.macro_calls().for_each(|(_ast_id, call_id)| self.collect_macro_call(call_id));
1442    }
1443}
1444
1445impl<'db> AnyDiagnostic<'db> {
1446    fn body_validation_diagnostic(
1447        db: &'db dyn HirDatabase,
1448        diagnostic: BodyValidationDiagnostic<'db>,
1449        source_map: &hir_def::expr_store::BodySourceMap,
1450    ) -> Option<AnyDiagnostic<'db>> {
1451        match diagnostic {
1452            BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
1453                let variant_data = variant.fields(db);
1454                let missed_fields = missed_fields
1455                    .into_iter()
1456                    .map(|idx| {
1457                        (
1458                            variant_data.fields()[idx].name.clone(),
1459                            Field { parent: variant.into(), id: idx },
1460                        )
1461                    })
1462                    .collect();
1463
1464                let record = match record {
1465                    Either::Left(record_expr) => source_map.expr_syntax(record_expr).ok()?,
1466                    Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
1467                };
1468                let file = record.file_id;
1469                let root = record.file_syntax(db);
1470                match record.value.to_node(&root) {
1471                    Either::Left(ast::Expr::RecordExpr(record_expr))
1472                        if record_expr.record_expr_field_list().is_some() =>
1473                    {
1474                        let field_list_parent_path =
1475                            record_expr.path().map(|path| AstPtr::new(&path));
1476                        return Some(
1477                            MissingFields {
1478                                file,
1479                                field_list_parent: AstPtr::new(&Either::Left(record_expr)),
1480                                field_list_parent_path,
1481                                missed_fields,
1482                            }
1483                            .into(),
1484                        );
1485                    }
1486                    Either::Right(ast::Pat::RecordPat(record_pat))
1487                        if record_pat.record_pat_field_list().is_some() =>
1488                    {
1489                        let field_list_parent_path =
1490                            record_pat.path().map(|path| AstPtr::new(&path));
1491                        return Some(
1492                            MissingFields {
1493                                file,
1494                                field_list_parent: AstPtr::new(&Either::Right(record_pat)),
1495                                field_list_parent_path,
1496                                missed_fields,
1497                            }
1498                            .into(),
1499                        );
1500                    }
1501                    _ => {}
1502                }
1503            }
1504            BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
1505                if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
1506                    return Some(
1507                        ReplaceFilterMapNextWithFindMap {
1508                            file: next_source_ptr.file_id,
1509                            next_expr: next_source_ptr.value.cast()?,
1510                        }
1511                        .into(),
1512                    );
1513                }
1514            }
1515            BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
1516                if let Ok(source_ptr) = source_map.expr_syntax(match_expr)
1517                    && let root = source_ptr.file_syntax(db)
1518                    && let Either::Left(ast::Expr::MatchExpr(match_expr)) =
1519                        source_ptr.value.to_node(&root)
1520                    && let Some(scrut_expr) = match_expr.expr()
1521                    && match_expr.match_arm_list().is_some()
1522                {
1523                    return Some(
1524                        MissingMatchArms {
1525                            scrutinee_expr: InFile::new(
1526                                source_ptr.file_id,
1527                                AstPtr::new(&scrut_expr),
1528                            ),
1529                            uncovered_patterns,
1530                        }
1531                        .into(),
1532                    );
1533                }
1534            }
1535            BodyValidationDiagnostic::NonExhaustiveLet { pat, uncovered_patterns } => {
1536                if let Ok(source_ptr) = source_map.pat_syntax(pat)
1537                    && let Some(ast_pat) = source_ptr.value.cast::<ast::Pat>()
1538                {
1539                    return Some(
1540                        NonExhaustiveLet {
1541                            pat: InFile::new(source_ptr.file_id, ast_pat),
1542                            uncovered_patterns,
1543                        }
1544                        .into(),
1545                    );
1546                }
1547            }
1548            BodyValidationDiagnostic::RemoveTrailingReturn { return_expr } => {
1549                if let Ok(source_ptr) = source_map.expr_syntax(return_expr)
1550                    // Filters out desugared return expressions (e.g. desugared try operators).
1551                    && let Some(ptr) = source_ptr.value.cast::<ast::ReturnExpr>()
1552                {
1553                    return Some(
1554                        RemoveTrailingReturn { return_expr: InFile::new(source_ptr.file_id, ptr) }
1555                            .into(),
1556                    );
1557                }
1558            }
1559            BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr } => {
1560                if let Ok(source_ptr) = source_map.expr_syntax(if_expr)
1561                    && let Some(ptr) = source_ptr.value.cast::<ast::IfExpr>()
1562                {
1563                    return Some(
1564                        RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) }
1565                            .into(),
1566                    );
1567                }
1568            }
1569            BodyValidationDiagnostic::UnusedMustUse { expr, message } => {
1570                if let Ok(source_ptr) = source_map.expr_syntax(expr) {
1571                    return Some(UnusedMustUse { expr: source_ptr, message }.into());
1572                }
1573            }
1574        }
1575        None
1576    }
1577
1578    fn inference_diagnostic(
1579        db: &'db dyn HirDatabase,
1580        krate: base_db::Crate,
1581        edition: Edition,
1582        d: &'db InferenceDiagnostic,
1583        source_map: &ExpressionStoreSourceMap,
1584        type_owner: TypeOwnerId,
1585    ) -> Option<AnyDiagnostic<'db>> {
1586        let expr_syntax = |expr| Self::expr_syntax(expr, source_map);
1587        let pat_syntax = |pat| Self::pat_syntax(pat, source_map);
1588        let expr_or_pat_syntax = |id| match id {
1589            ExprOrPatId::ExprId(expr) => expr_syntax(expr),
1590            ExprOrPatId::PatId(pat) => pat_syntax(pat),
1591        };
1592        let new_ty = |ty| Type { owner: type_owner, ty: EarlyBinder::bind(ty) };
1593        let span_syntax = |span| Self::span_syntax(span, source_map);
1594        Some(match d {
1595            &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
1596                let expr_or_pat = match expr.unpack() {
1597                    ExprOrPatId::ExprId(expr) => {
1598                        source_map.field_syntax(expr).map(AstPtr::wrap_left)
1599                    }
1600                    ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
1601                };
1602                let private = private.map(|id| Field { id, parent: variant.into() });
1603                NoSuchField { field: expr_or_pat, private, variant }.into()
1604            }
1605            &InferenceDiagnostic::MismatchedArrayPatLen { pat, expected, found, has_rest } => {
1606                let pat = pat_syntax(pat)?.map(Into::into);
1607                MismatchedArrayPatLen { pat, expected, found, has_rest }.into()
1608            }
1609            &InferenceDiagnostic::ArrayPatternWithoutFixedLength { pat } => {
1610                let pat = pat_syntax(pat)?.map(Into::into);
1611                ArrayPatternWithoutFixedLength { pat }.into()
1612            }
1613            InferenceDiagnostic::ExpectedArrayOrSlicePat { pat, found } => {
1614                let pat = pat_syntax(*pat)?.map(Into::into);
1615                ExpectedArrayOrSlicePat {
1616                    pat,
1617                    found: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) },
1618                }
1619                .into()
1620            }
1621            &InferenceDiagnostic::InvalidRangePatType { pat } => {
1622                let pat = pat_syntax(pat)?.map(Into::into);
1623                InvalidRangePatType { pat }.into()
1624            }
1625            &InferenceDiagnostic::DuplicateField { field: expr, variant } => {
1626                let expr_or_pat = match expr.unpack() {
1627                    ExprOrPatId::ExprId(expr) => {
1628                        source_map.field_syntax(expr).map(AstPtr::wrap_left)
1629                    }
1630                    ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
1631                };
1632                DuplicateField { field: expr_or_pat, variant: variant.into() }.into()
1633            }
1634            &InferenceDiagnostic::MismatchedArgCount {
1635                call_expr,
1636                expected,
1637                found,
1638                is_fn_trait_call,
1639            } => MismatchedArgCount {
1640                call_expr: expr_syntax(call_expr)?,
1641                expected,
1642                found,
1643                is_fn_trait_call,
1644            }
1645            .into(),
1646            &InferenceDiagnostic::PrivateField { expr, field } => {
1647                let expr = expr_syntax(expr)?;
1648                let field = field.into();
1649                PrivateField { expr, field }.into()
1650            }
1651            &InferenceDiagnostic::PrivateAssocItem { id, item } => {
1652                let expr_or_pat = expr_or_pat_syntax(id.unpack())?;
1653                let item = item.into();
1654                PrivateAssocItem { expr_or_pat, item }.into()
1655            }
1656            InferenceDiagnostic::ExpectedFunction { call_expr, found } => {
1657                let call_expr = expr_syntax(*call_expr)?;
1658                ExpectedFunction { call: call_expr, found: new_ty(found.as_ref()) }.into()
1659            }
1660            InferenceDiagnostic::UnresolvedField {
1661                expr,
1662                receiver,
1663                name,
1664                method_with_same_name_exists,
1665            } => {
1666                let expr = expr_syntax(*expr)?;
1667                UnresolvedField {
1668                    expr,
1669                    name: name.clone(),
1670                    receiver: new_ty(receiver.as_ref()),
1671                    method_with_same_name_exists: *method_with_same_name_exists,
1672                }
1673                .into()
1674            }
1675            InferenceDiagnostic::UnresolvedMethodCall {
1676                expr,
1677                receiver,
1678                name,
1679                field_with_same_name,
1680                assoc_func_with_same_name,
1681            } => {
1682                let expr = expr_syntax(*expr)?;
1683                UnresolvedMethodCall {
1684                    expr,
1685                    name: name.clone(),
1686                    receiver: new_ty(receiver.as_ref()),
1687                    field_with_same_name: field_with_same_name
1688                        .as_ref()
1689                        .map(|ty| new_ty(ty.as_ref())),
1690                    assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into),
1691                }
1692                .into()
1693            }
1694            &InferenceDiagnostic::UnresolvedAssocItem { id } => {
1695                let expr_or_pat = expr_or_pat_syntax(id.unpack())?;
1696                UnresolvedAssocItem { expr_or_pat }.into()
1697            }
1698            &InferenceDiagnostic::UnresolvedIdent { id } => {
1699                let node = match id.unpack() {
1700                    ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) {
1701                        Ok(syntax) => syntax.map(|it| (it, None)),
1702                        Err(SyntheticSyntax) => source_map
1703                            .format_args_implicit_capture(id)?
1704                            .map(|(node, range)| (node.wrap_left(), Some(range))),
1705                    },
1706                    ExprOrPatId::PatId(id) => pat_syntax(id)?.map(|it| (it, None)),
1707                };
1708                UnresolvedIdent { node }.into()
1709            }
1710            &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
1711                let expr = expr_syntax(expr)?;
1712                BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()
1713            }
1714            &InferenceDiagnostic::NonExhaustiveRecordExpr { expr } => {
1715                NonExhaustiveRecordExpr { expr: expr_syntax(expr)? }.into()
1716            }
1717            &InferenceDiagnostic::NonExhaustiveRecordPat { pat, variant } => {
1718                let pat = pat_syntax(pat)?.map(Into::into);
1719                NonExhaustiveRecordPat { pat, variant: variant.into() }.into()
1720            }
1721            &InferenceDiagnostic::UnionPatMustHaveExactlyOneField { pat } => {
1722                let pat = pat_syntax(pat)?.map(Into::into);
1723                UnionPatMustHaveExactlyOneField { pat }.into()
1724            }
1725            &InferenceDiagnostic::UnionPatHasRest { pat } => {
1726                let pat = pat_syntax(pat)?.map(Into::into);
1727                UnionPatHasRest { pat }.into()
1728            }
1729            &InferenceDiagnostic::FunctionalRecordUpdateOnNonStruct { base_expr } => {
1730                FunctionalRecordUpdateOnNonStruct { base_expr: expr_syntax(base_expr)? }.into()
1731            }
1732            InferenceDiagnostic::TypedHole { expr, expected } => {
1733                let expr = expr_syntax(*expr)?;
1734                TypedHole { expr, expected: new_ty(expected.as_ref()) }.into()
1735            }
1736            &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => {
1737                let InFile { file_id, value } = pat_syntax(pat)?;
1738                // cast from Either<Pat, SelfParam> -> Either<_, Pat>
1739                let ptr = AstPtr::try_from_raw(value.syntax_node_ptr())?;
1740                let expr_or_pat = InFile { file_id, value: ptr };
1741                MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into()
1742            }
1743            InferenceDiagnostic::CastToUnsized { expr, cast_ty } => {
1744                let expr = expr_syntax(*expr)?;
1745                CastToUnsized { expr, cast_ty: new_ty(cast_ty.as_ref()) }.into()
1746            }
1747            InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => {
1748                let expr = expr_syntax(*expr)?;
1749                let expr_ty = new_ty(expr_ty.as_ref());
1750                let cast_ty = new_ty(cast_ty.as_ref());
1751                InvalidCast { expr, error: *error, expr_ty, cast_ty }.into()
1752            }
1753            InferenceDiagnostic::CannotBeDereferenced { expr, found } => {
1754                let expr = expr_syntax(*expr)?;
1755                CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into()
1756            }
1757            InferenceDiagnostic::UnaryOperatorCannotBeApplied { expr, op, found } => {
1758                let expr = expr_syntax(*expr)?;
1759                UnaryOperatorCannotBeApplied { expr, op: *op, found: new_ty(found.as_ref()) }.into()
1760            }
1761            InferenceDiagnostic::MutRefInImmRefPat { pat } => {
1762                let pat = pat_syntax(*pat)?.map(Into::into);
1763                MutRefInImmRefPat { pat }.into()
1764            }
1765            InferenceDiagnostic::CannotImplicitlyDerefTraitObject { pat, found } => {
1766                let pat = pat_syntax(*pat)?.map(Into::into);
1767                CannotImplicitlyDerefTraitObject { pat, found: new_ty(found.as_ref()) }.into()
1768            }
1769            InferenceDiagnostic::CannotIndexInto { expr, found } => {
1770                let expr = expr_syntax(*expr)?;
1771                CannotIndexInto { expr, found: new_ty(found.as_ref()) }.into()
1772            }
1773            InferenceDiagnostic::TyDiagnostic { diag } => {
1774                Self::ty_diagnostic(diag, source_map, db)?
1775            }
1776            InferenceDiagnostic::PathDiagnostic { node, diag } => {
1777                let source = expr_or_pat_syntax(node.unpack())?;
1778                let syntax = source.value.to_node(&source.file_id.parse_or_expand(db));
1779                let path = match_ast! {
1780                    match (syntax.syntax()) {
1781                        ast::RecordExpr(it) => it.path()?,
1782                        ast::RecordPat(it) => it.path()?,
1783                        ast::TupleStructPat(it) => it.path()?,
1784                        ast::PathExpr(it) => it.path()?,
1785                        ast::PathPat(it) => it.path()?,
1786                        _ => return None,
1787                    }
1788                };
1789                Self::path_diagnostic(diag, source.with_value(path))?
1790            }
1791            &InferenceDiagnostic::MethodCallIncorrectGenericsLen {
1792                expr,
1793                provided_count,
1794                expected_count,
1795                kind,
1796                def,
1797            } => {
1798                let syntax = expr_syntax(expr)?;
1799                let file_id = syntax.file_id;
1800                let syntax =
1801                    syntax.with_value(syntax.value.cast::<ast::MethodCallExpr>()?).to_node(db);
1802                let generics_or_name = syntax
1803                    .generic_arg_list()
1804                    .map(Either::Left)
1805                    .or_else(|| syntax.name_ref().map(Either::Right))?;
1806                let generics_or_name = InFile::new(file_id, AstPtr::new(&generics_or_name));
1807                IncorrectGenericsLen {
1808                    generics_or_segment: generics_or_name,
1809                    kind,
1810                    provided: provided_count,
1811                    expected: expected_count,
1812                    def: def.into(),
1813                }
1814                .into()
1815            }
1816            &InferenceDiagnostic::MethodCallIncorrectGenericsOrder {
1817                expr,
1818                param_id,
1819                arg_idx,
1820                has_self_arg,
1821            } => {
1822                let syntax = expr_syntax(expr)?;
1823                let file_id = syntax.file_id;
1824                let syntax =
1825                    syntax.with_value(syntax.value.cast::<ast::MethodCallExpr>()?).to_node(db);
1826                let generic_args = syntax.generic_arg_list()?;
1827                let provided_arg = hir_generic_arg_to_ast(&generic_args, arg_idx, has_self_arg)?;
1828                let provided_arg = InFile::new(file_id, AstPtr::new(&provided_arg));
1829                let expected_kind = GenericArgKind::from_id(param_id);
1830                IncorrectGenericsOrder { provided_arg, expected_kind }.into()
1831            }
1832            &InferenceDiagnostic::InvalidLhsOfAssignment { lhs } => {
1833                let lhs = expr_syntax(lhs)?;
1834                InvalidLhsOfAssignment { lhs }.into()
1835            }
1836            &InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr } => {
1837                MethodCallIllegalSizedBound { call_expr: expr_syntax(call_expr)? }.into()
1838            }
1839            &InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => {
1840                let at_point = span_syntax(at_point)?;
1841                let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() {
1842                    rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(new_ty(ty)),
1843                    // FIXME: Printing the const to string is definitely not the correct thing to do here.
1844                    rustc_type_ir::GenericArgKind::Const(konst) => Either::Right(
1845                        konst
1846                            .display(db, DisplayTarget::from_crate_and_edition(db, krate, edition))
1847                            .to_string(),
1848                    ),
1849                    rustc_type_ir::GenericArgKind::Lifetime(_) => {
1850                        unreachable!("we currently don't emit TypeMustBeKnown for lifetimes")
1851                    }
1852                });
1853                TypeMustBeKnown { at_point, top_term }.into()
1854            }
1855            &InferenceDiagnostic::UnionExprMustHaveExactlyOneField { expr } => {
1856                let expr = expr_syntax(expr)?;
1857                UnionExprMustHaveExactlyOneField { expr }.into()
1858            }
1859            InferenceDiagnostic::TypeMismatch { node, expected, found } => {
1860                let expr_or_pat = expr_or_pat_syntax(node.unpack())?;
1861                TypeMismatch {
1862                    expr_or_pat,
1863                    expected: Type { owner: type_owner, ty: EarlyBinder::bind(expected.as_ref()) },
1864                    actual: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) },
1865                }
1866                .into()
1867            }
1868            InferenceDiagnostic::SolverDiagnostic(d) => {
1869                let span = span_syntax(d.span)?;
1870                Self::solver_diagnostic(db, &d.kind, span, type_owner)?
1871            }
1872            InferenceDiagnostic::ExplicitDropMethodUse { kind } => {
1873                let expr_or_path = match kind {
1874                    ExplicitDropMethodUseKind::MethodCall(expr) => {
1875                        let expr = expr_syntax(*expr)?;
1876                        let expr = expr.with_value(expr.value.cast::<ast::MethodCallExpr>()?);
1877                        Either::Left(expr)
1878                    }
1879                    ExplicitDropMethodUseKind::Path(path_expr_id) => {
1880                        let syntax = expr_or_pat_syntax(path_expr_id.unpack())?;
1881                        let file_id = syntax.file_id;
1882                        let syntax =
1883                            syntax.with_value(syntax.value.cast::<ast::PathExpr>()?).to_node(db);
1884                        let path = syntax.path()?;
1885                        let path = InFile::new(file_id, AstPtr::new(&path));
1886                        Either::Right(path)
1887                    }
1888                };
1889                ExplicitDropMethodUse { expr_or_path }.into()
1890            }
1891            InferenceDiagnostic::MutableRefBinding { pat } => {
1892                let pat = pat_syntax(*pat)?.map(Into::into);
1893                MutableRefBinding { pat }.into()
1894            }
1895            &InferenceDiagnostic::YieldOutsideCoroutine { expr } => {
1896                YieldOutsideCoroutine { expr: expr_syntax(expr)? }.into()
1897            }
1898            &InferenceDiagnostic::ReturnOutsideFunction { expr, kind } => {
1899                ReturnOutsideFunction { expr: expr_syntax(expr)?, kind }.into()
1900            }
1901            &InferenceDiagnostic::RecordMissingFields { record, variant, ref missed_fields } => {
1902                let record = expr_or_pat_syntax(record)?;
1903                let file = record.file_id;
1904                let root = record.file_syntax(db);
1905                let variant_data = variant.fields(db);
1906                let missed_fields = missed_fields
1907                    .iter()
1908                    .map(|&idx| {
1909                        (
1910                            variant_data.fields()[idx].name.clone(),
1911                            Field { parent: variant.into(), id: idx },
1912                        )
1913                    })
1914                    .collect();
1915                match record.value.to_node(&root) {
1916                    Either::Left(ast::Expr::RecordExpr(record_expr))
1917                        if record_expr.record_expr_field_list().is_some() =>
1918                    {
1919                        let field_list_parent_path =
1920                            record_expr.path().map(|path| AstPtr::new(&path));
1921                        return Some(
1922                            MissingFields {
1923                                file,
1924                                field_list_parent: AstPtr::new(&Either::Left(record_expr)),
1925                                field_list_parent_path,
1926                                missed_fields,
1927                            }
1928                            .into(),
1929                        );
1930                    }
1931                    Either::Right(ast::Pat::RecordPat(record_pat))
1932                        if record_pat.record_pat_field_list().is_some() =>
1933                    {
1934                        let field_list_parent_path =
1935                            record_pat.path().map(|path| AstPtr::new(&path));
1936                        MissingFields {
1937                            file,
1938                            field_list_parent: AstPtr::new(&Either::Right(record_pat)),
1939                            field_list_parent_path,
1940                            missed_fields,
1941                        }
1942                        .into()
1943                    }
1944                    _ => return None,
1945                }
1946            }
1947            InferenceDiagnostic::MatchInheritedImmRefWithMutRefPat { pat } => {
1948                let pat = pat_syntax(*pat)?.map(Into::into);
1949                MatchInheritedImmRefWithMutRefPat { pat }.into()
1950            }
1951            InferenceDiagnostic::InvalidPatPathRes { pat, res } => {
1952                let pat = pat_syntax(*pat)?.map(Into::into);
1953                let kind = match res {
1954                    ValueNs::FunctionId(_) => InvalidPatPathResKind::Function,
1955                    ValueNs::GenericParam(_) => InvalidPatPathResKind::GenericParam,
1956                    ValueNs::ImplSelf(_) => InvalidPatPathResKind::ImplSelf,
1957                    ValueNs::LocalBinding(_) => InvalidPatPathResKind::LocalBinding,
1958                    ValueNs::StaticId(_) => InvalidPatPathResKind::Static,
1959                    ValueNs::ConstId(_) | ValueNs::EnumVariantId(_) | ValueNs::StructId(_) => {
1960                        return None;
1961                    }
1962                };
1963                InvalidPatPathRes { pat, kind }.into()
1964            }
1965        })
1966    }
1967
1968    fn solver_diagnostic(
1969        db: &'db dyn HirDatabase,
1970        d: &'db SolverDiagnosticKind,
1971        span: SpanSyntax,
1972        type_owner: TypeOwnerId,
1973    ) -> Option<AnyDiagnostic<'db>> {
1974        let interner = DbInterner::new_no_crate(db);
1975        Some(match d {
1976            SolverDiagnosticKind::TraitUnimplemented {
1977                trait_predicate,
1978                parent_trait_predicates,
1979            } => {
1980                let trait_predicate = crate::TraitPredicate {
1981                    inner: trait_predicate.get(interner),
1982                    owner: type_owner,
1983                };
1984                let parent_trait_predicates = parent_trait_predicates
1985                    .iter()
1986                    .map(|trait_predicate| crate::TraitPredicate {
1987                        inner: trait_predicate.get(interner),
1988                        owner: type_owner,
1989                    })
1990                    .collect();
1991                UnimplementedTrait { span, trait_predicate, parent_trait_predicates }.into()
1992            }
1993        })
1994    }
1995
1996    fn path_diagnostic(
1997        diag: &PathLoweringDiagnostic,
1998        path: InFile<ast::Path>,
1999    ) -> Option<AnyDiagnostic<'db>> {
2000        Some(match *diag {
2001            PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
2002                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
2003
2004                if let Some(rtn) = segment.return_type_syntax() {
2005                    // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
2006                    return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
2007                }
2008
2009                let args = if let Some(generics) = segment.generic_arg_list() {
2010                    AstPtr::new(&generics).wrap_left()
2011                } else {
2012                    AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right()
2013                };
2014                let args = path.with_value(args);
2015                GenericArgsProhibited { args, reason }.into()
2016            }
2017            PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment } => {
2018                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
2019
2020                if let Some(rtn) = segment.return_type_syntax() {
2021                    // RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
2022                    return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
2023                }
2024
2025                let args = AstPtr::new(&segment.parenthesized_arg_list()?);
2026                let args = path.with_value(args);
2027                ParenthesizedGenericArgsWithoutFnTrait { args }.into()
2028            }
2029            PathLoweringDiagnostic::IncorrectGenericsLen {
2030                generics_source,
2031                provided_count,
2032                expected_count,
2033                kind,
2034                def,
2035            } => {
2036                let generics_or_segment =
2037                    path_generics_source_to_ast(&path.value, generics_source)?;
2038                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
2039                IncorrectGenericsLen {
2040                    generics_or_segment,
2041                    kind,
2042                    provided: provided_count,
2043                    expected: expected_count,
2044                    def: def.into(),
2045                }
2046                .into()
2047            }
2048            PathLoweringDiagnostic::IncorrectGenericsOrder {
2049                generics_source,
2050                param_id,
2051                arg_idx,
2052                has_self_arg,
2053            } => {
2054                let generic_args =
2055                    path_generics_source_to_ast(&path.value, generics_source)?.left()?;
2056                let provided_arg = hir_generic_arg_to_ast(&generic_args, arg_idx, has_self_arg)?;
2057                let provided_arg = path.with_value(AstPtr::new(&provided_arg));
2058                let expected_kind = GenericArgKind::from_id(param_id);
2059                IncorrectGenericsOrder { provided_arg, expected_kind }.into()
2060            }
2061            PathLoweringDiagnostic::MissingLifetime { generics_source, expected_count, def }
2062            | PathLoweringDiagnostic::ElisionFailure { generics_source, expected_count, def } => {
2063                let generics_or_segment =
2064                    path_generics_source_to_ast(&path.value, generics_source)?;
2065                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
2066                MissingLifetime { generics_or_segment, expected: expected_count, def: def.into() }
2067                    .into()
2068            }
2069            PathLoweringDiagnostic::ElidedLifetimesInPath {
2070                generics_source,
2071                expected_count,
2072                def,
2073                hard_error,
2074            } => {
2075                let generics_or_segment =
2076                    path_generics_source_to_ast(&path.value, generics_source)?;
2077                let generics_or_segment = path.with_value(AstPtr::new(&generics_or_segment));
2078                ElidedLifetimesInPath {
2079                    generics_or_segment,
2080                    expected: expected_count,
2081                    def: def.into(),
2082                    hard_error,
2083                }
2084                .into()
2085            }
2086            PathLoweringDiagnostic::GenericDefaultRefersToSelf { segment } => {
2087                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
2088                let segment = path.with_value(AstPtr::new(&segment));
2089                GenericDefaultRefersToSelf { segment }.into()
2090            }
2091            PathLoweringDiagnostic::UnresolvedAssociatedType { segment } => {
2092                let segment = hir_segment_to_ast_segment(&path.value, segment)?;
2093                let segment = path.with_value(AstPtr::new(&segment));
2094                UnresolvedAssociatedType { segment }.into()
2095            }
2096        })
2097    }
2098
2099    fn expr_syntax(
2100        expr: ExprId,
2101        source_map: &ExpressionStoreSourceMap,
2102    ) -> Option<InFile<ExprOrPatPtr>> {
2103        source_map
2104            .expr_syntax(expr)
2105            .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr"))
2106            .ok()
2107    }
2108
2109    fn pat_syntax(
2110        pat: PatId,
2111        source_map: &ExpressionStoreSourceMap,
2112    ) -> Option<InFile<ExprOrPatPtr>> {
2113        source_map
2114            .pat_syntax(pat)
2115            .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern"))
2116            .ok()
2117    }
2118
2119    fn type_syntax(
2120        type_ref: TypeRefId,
2121        source_map: &ExpressionStoreSourceMap,
2122    ) -> Option<InFile<AstPtr<ast::Type>>> {
2123        source_map
2124            .type_syntax(type_ref)
2125            .inspect_err(|_| stdx::never!("inference diagnostic in desugared type"))
2126            .ok()
2127    }
2128
2129    fn span_syntax(
2130        span: hir_ide::Span,
2131        source_map: &ExpressionStoreSourceMap,
2132    ) -> Option<InFile<AstPtr<SpanAst>>> {
2133        Some(match span {
2134            hir_ide::Span::ExprId(idx) => Self::expr_syntax(idx, source_map)?.map(|it| it.upcast()),
2135            hir_ide::Span::PatId(idx) => Self::pat_syntax(idx, source_map)?.map(|it| it.upcast()),
2136            hir_ide::Span::TypeRefId(idx) => {
2137                Self::type_syntax(idx, source_map)?.map(|it| it.upcast())
2138            }
2139            hir_ide::Span::BindingId(idx) => {
2140                let &pat = source_map.patterns_for_binding(idx).first()?;
2141                Self::pat_syntax(pat, source_map)?.map(|it| it.upcast())
2142            }
2143            hir_ide::Span::Dummy => {
2144                never!("should never create a diagnostic for dummy spans");
2145                return None;
2146            }
2147        })
2148    }
2149
2150    fn ty_diagnostic(
2151        diag: &TyLoweringDiagnostic,
2152        source_map: &ExpressionStoreSourceMap,
2153        db: &'db dyn HirDatabase,
2154    ) -> Option<AnyDiagnostic<'db>> {
2155        Some(match diag {
2156            TyLoweringDiagnostic::PathDiagnostic { source, diag } => {
2157                let source = Self::type_syntax(*source, source_map)?;
2158                let syntax = source.value.to_node(&source.file_id.parse_or_expand(db));
2159                let ast::Type::PathType(syntax) = syntax else { return None };
2160                Self::path_diagnostic(diag, source.with_value(syntax.path()?))?
2161            }
2162            TyLoweringDiagnostic::InferVarsNotAllowed { source } => {
2163                let source = Self::span_syntax(*source, source_map)?;
2164                InferVarsNotAllowed { node: source.map(Into::into) }.into()
2165            }
2166        })
2167    }
2168}
2169
2170fn path_generics_source_to_ast(
2171    path: &ast::Path,
2172    generics_source: PathGenericsSource,
2173) -> Option<Either<ast::GenericArgList, ast::NameRef>> {
2174    Some(match generics_source {
2175        PathGenericsSource::Segment(segment) => {
2176            let segment = hir_segment_to_ast_segment(path, segment)?;
2177            segment
2178                .generic_arg_list()
2179                .map(Either::Left)
2180                .or_else(|| segment.name_ref().map(Either::Right))?
2181        }
2182        PathGenericsSource::AssocType { segment, assoc_type } => {
2183            let segment = hir_segment_to_ast_segment(path, segment)?;
2184            let segment_args = segment.generic_arg_list()?;
2185            let assoc = hir_assoc_type_binding_to_ast(&segment_args, assoc_type)?;
2186            assoc
2187                .generic_arg_list()
2188                .map(Either::Left)
2189                .or_else(|| assoc.name_ref().map(Either::Right))?
2190        }
2191    })
2192}