1use 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 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 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#[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 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 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 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 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 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 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 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 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 (true, _, true, _) |
1023 (true, false, _, false) => self.acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
1025 (false, true, false, _) |
1027 (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 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 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 continue;
1165 }
1166 self.emit_def_diagnostic(&diag.kind);
1167 }
1168
1169 if !def.is_block_module(self.db) {
1170 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 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 }
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 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 && 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 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 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 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 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}