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 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 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 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#[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 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 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 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 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 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 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 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 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 (true, _, true, _) |
994 (true, false, _, false) => self.acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
996 (false, true, false, _) |
998 (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 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 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 continue;
1136 }
1137 self.emit_def_diagnostic(&diag.kind);
1138 }
1139
1140 if !def.is_block_module(self.db) {
1141 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 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 }
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 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 && 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 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 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 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 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}