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