Skip to content

Commit 5a650d4

Browse files
committed
Generally optimize diagnostics performance
1 parent 7e2ddaa commit 5a650d4

File tree

15 files changed

+115
-85
lines changed

15 files changed

+115
-85
lines changed

src/tools/rust-analyzer/crates/base-db/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub trait Upcast<T: ?Sized> {
4545

4646
pub const DEFAULT_FILE_TEXT_LRU_CAP: usize = 16;
4747
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
48-
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 1024;
48+
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 2024;
4949

5050
pub trait FileLoader {
5151
/// Text of the file.

src/tools/rust-analyzer/crates/hir-def/src/data.rs

+2
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ pub struct ConstData {
510510
pub type_ref: Interned<TypeRef>,
511511
pub visibility: RawVisibility,
512512
pub rustc_allow_incoherent_impl: bool,
513+
pub has_body: bool,
513514
}
514515

515516
impl ConstData {
@@ -533,6 +534,7 @@ impl ConstData {
533534
type_ref: konst.type_ref.clone(),
534535
visibility,
535536
rustc_allow_incoherent_impl,
537+
has_body: konst.has_body,
536538
})
537539
}
538540
}

src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ use crate::{
2626
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
2727
type_ref::TypeRef,
2828
visibility::RawVisibility,
29-
AdtId, EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId,
30-
VariantId,
29+
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
3130
};
3231

3332
/// Note that we use `StructData` for unions as well!
@@ -380,6 +379,7 @@ impl VariantData {
380379
}
381380
}
382381

382+
#[allow(clippy::self_named_constructors)]
383383
pub(crate) fn variant_data(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> {
384384
match id {
385385
VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),

src/tools/rust-analyzer/crates/hir-def/src/db.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ use crate::{
2222
lang_item::{self, LangItem, LangItemTarget, LangItems},
2323
nameres::{diagnostics::DefDiagnostics, DefMap},
2424
visibility::{self, Visibility},
25-
AdtId, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc,
26-
DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc,
27-
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc,
28-
InTypeConstId, InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId,
29-
MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId,
30-
StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
31-
UnionLoc, UseId, UseLoc, VariantId,
25+
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
26+
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
27+
ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId,
28+
InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc,
29+
MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc,
30+
TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
31+
UseId, UseLoc, VariantId,
3232
};
3333

3434
#[salsa::query_group(InternDatabaseStorage)]

src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs

+1
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ pub struct Const {
716716
pub visibility: RawVisibilityId,
717717
pub type_ref: Interned<TypeRef>,
718718
pub ast_id: FileAstId<ast::Const>,
719+
pub has_body: bool,
719720
}
720721

721722
#[derive(Debug, Clone, Eq, PartialEq)]

src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ impl<'a> Ctx<'a> {
446446
let type_ref = self.lower_type_ref_opt(konst.ty());
447447
let visibility = self.lower_visibility(konst);
448448
let ast_id = self.source_ast_id_map.ast_id(konst);
449-
let res = Const { name, visibility, type_ref, ast_id };
449+
let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
450450
id(self.data().consts.alloc(res))
451451
}
452452

src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ impl Printer<'_> {
357357
wln!(self, "}}");
358358
}
359359
ModItem::Const(it) => {
360-
let Const { name, visibility, type_ref, ast_id } = &self.tree[it];
360+
let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
361361
self.print_ast_id(ast_id.erase());
362362
self.print_visibility(*visibility);
363363
w!(self, "const ");

src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod allow {
4343
}
4444

4545
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
46-
let _p = tracing::span!(tracing::Level::INFO, "validate_module_item").entered();
46+
let _p = tracing::span!(tracing::Level::INFO, "incorrect_case").entered();
4747
let mut validator = DeclValidator::new(db);
4848
validator.validate_item(owner);
4949
validator.sink

src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs

+45-37
Original file line numberDiff line numberDiff line change
@@ -191,45 +191,45 @@ impl ExprValidator {
191191
let pattern_arena = Arena::new();
192192
let mut m_arms = Vec::with_capacity(arms.len());
193193
let mut has_lowering_errors = false;
194+
// Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
195+
// preferred to avoid the chance of false positives.
194196
for arm in arms {
195-
if let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) {
196-
// We only include patterns whose type matches the type
197-
// of the scrutinee expression. If we had an InvalidMatchArmPattern
198-
// diagnostic or similar we could raise that in an else
199-
// block here.
200-
//
201-
// When comparing the types, we also have to consider that rustc
202-
// will automatically de-reference the scrutinee expression type if
203-
// necessary.
204-
//
205-
// FIXME we should use the type checker for this.
206-
if (pat_ty == scrut_ty
207-
|| scrut_ty
208-
.as_reference()
209-
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
210-
.unwrap_or(false))
211-
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
212-
{
213-
// If we had a NotUsefulMatchArm diagnostic, we could
214-
// check the usefulness of each pattern as we added it
215-
// to the matrix here.
216-
let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
217-
let m_arm = pat_analysis::MatchArm {
218-
pat: pattern_arena.alloc(pat),
219-
has_guard: arm.guard.is_some(),
220-
arm_data: (),
221-
};
222-
m_arms.push(m_arm);
223-
if !has_lowering_errors {
224-
continue;
225-
}
197+
let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else {
198+
return;
199+
};
200+
201+
// We only include patterns whose type matches the type
202+
// of the scrutinee expression. If we had an InvalidMatchArmPattern
203+
// diagnostic or similar we could raise that in an else
204+
// block here.
205+
//
206+
// When comparing the types, we also have to consider that rustc
207+
// will automatically de-reference the scrutinee expression type if
208+
// necessary.
209+
//
210+
// FIXME we should use the type checker for this.
211+
if (pat_ty == scrut_ty
212+
|| scrut_ty
213+
.as_reference()
214+
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
215+
.unwrap_or(false))
216+
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
217+
{
218+
// If we had a NotUsefulMatchArm diagnostic, we could
219+
// check the usefulness of each pattern as we added it
220+
// to the matrix here.
221+
let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
222+
let m_arm = pat_analysis::MatchArm {
223+
pat: pattern_arena.alloc(pat),
224+
has_guard: arm.guard.is_some(),
225+
arm_data: (),
226+
};
227+
m_arms.push(m_arm);
228+
if !has_lowering_errors {
229+
continue;
226230
}
227231
}
228-
229-
// If we can't resolve the type of a pattern, or the pattern type doesn't
230-
// fit the match expression, we skip this diagnostic. Skipping the entire
231-
// diagnostic rather than just not including this match arm is preferred
232-
// to avoid the chance of false positives.
232+
// If the pattern type doesn't fit the match expression, we skip this diagnostic.
233233
cov_mark::hit!(validate_match_bailed_out);
234234
return;
235235
}
@@ -534,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
534534
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
535535
match infer.type_mismatch_for_pat(pat) {
536536
Some(_) => *has_type_mismatches = true,
537+
None if *has_type_mismatches => (),
537538
None => {
538-
body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
539+
let pat = &body[pat];
540+
if let Pat::ConstBlock(expr) | Pat::Lit(expr) = *pat {
541+
*has_type_mismatches |= infer.type_mismatch_for_expr(expr).is_some();
542+
if *has_type_mismatches {
543+
return;
544+
}
545+
}
546+
pat.walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
539547
}
540548
}
541549
}

src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use hir_def::{
55
body::Body,
66
hir::{Expr, ExprId, UnaryOp},
7-
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
7+
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
88
DefWithBodyId,
99
};
1010

@@ -13,9 +13,9 @@ use crate::{
1313
};
1414

1515
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
16-
let infer = db.infer(def);
17-
let mut res = Vec::new();
16+
let _p = tracing::span!(tracing::Level::INFO, "missing_unsafe",);
1817

18+
let mut res = Vec::new();
1919
let is_unsafe = match def {
2020
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
2121
DefWithBodyId::StaticId(_)
@@ -28,6 +28,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
2828
}
2929

3030
let body = db.body(def);
31+
let infer = db.infer(def);
3132
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
3233
if !expr.inside_unsafe_block {
3334
res.push(expr.expr);
@@ -51,14 +52,24 @@ pub fn unsafe_expressions(
5152
current: ExprId,
5253
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
5354
) {
54-
walk_unsafe(db, infer, def, body, current, false, unsafe_expr_cb)
55+
walk_unsafe(
56+
db,
57+
infer,
58+
body,
59+
&mut resolver_for_expr(db.upcast(), def, current),
60+
def,
61+
current,
62+
false,
63+
unsafe_expr_cb,
64+
)
5565
}
5666

5767
fn walk_unsafe(
5868
db: &dyn HirDatabase,
5969
infer: &InferenceResult,
60-
def: DefWithBodyId,
6170
body: &Body,
71+
resolver: &mut Resolver,
72+
def: DefWithBodyId,
6273
current: ExprId,
6374
inside_unsafe_block: bool,
6475
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
@@ -73,13 +84,14 @@ fn walk_unsafe(
7384
}
7485
}
7586
Expr::Path(path) => {
76-
let resolver = resolver_for_expr(db.upcast(), def, current);
87+
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
7788
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
7889
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
7990
if db.static_data(id).mutable {
8091
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
8192
}
8293
}
94+
resolver.reset_to_guard(g);
8395
}
8496
Expr::MethodCall { .. } => {
8597
if infer
@@ -97,13 +109,13 @@ fn walk_unsafe(
97109
}
98110
Expr::Unsafe { .. } => {
99111
return expr.walk_child_exprs(|child| {
100-
walk_unsafe(db, infer, def, body, child, true, unsafe_expr_cb);
112+
walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
101113
});
102114
}
103115
_ => {}
104116
}
105117

106118
expr.walk_child_exprs(|child| {
107-
walk_unsafe(db, infer, def, body, child, inside_unsafe_block, unsafe_expr_cb);
119+
walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb);
108120
});
109121
}

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

+1
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ pub struct InferenceResult {
432432
/// Whether there are any type-mismatching errors in the result.
433433
pub(crate) has_errors: bool,
434434
/// Interned common types to return references to.
435+
// FIXME: Move this into `InferenceContext`
435436
standard_types: InternedStandardTypes,
436437
/// Stores the types which were implicitly dereferenced in pattern binding modes.
437438
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,

src/tools/rust-analyzer/crates/hir/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,7 @@ impl Module {
548548
acc: &mut Vec<AnyDiagnostic>,
549549
style_lints: bool,
550550
) {
551-
let name = self.name(db);
552-
let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", ?name);
551+
let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", name = ?self.name(db));
553552
let def_map = self.id.def_map(db.upcast());
554553
for diag in def_map.diagnostics() {
555554
if diag.in_module != self.id.local_id {
@@ -684,7 +683,7 @@ impl Module {
684683
let items = &db.trait_data(trait_.into()).items;
685684
let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
686685
AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
687-
AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(),
686+
AssocItemId::ConstId(id) => !db.const_data(id).has_body,
688687
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
689688
});
690689
impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map(
@@ -1628,7 +1627,6 @@ impl DefWithBody {
16281627
acc: &mut Vec<AnyDiagnostic>,
16291628
style_lints: bool,
16301629
) {
1631-
db.unwind_if_cancelled();
16321630
let krate = self.module(db).id.krate();
16331631

16341632
let (body, source_map) = db.body_with_source_map(self.into());
@@ -1762,7 +1760,9 @@ impl DefWithBody {
17621760
need_mut = &mir::MutabilityReason::Not;
17631761
}
17641762
let local = Local { parent: self.into(), binding_id };
1765-
match (need_mut, local.is_mut(db)) {
1763+
let is_mut = body[binding_id].mode == BindingAnnotation::Mutable;
1764+
1765+
match (need_mut, is_mut) {
17661766
(mir::MutabilityReason::Unused, _) => {
17671767
let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_'));
17681768
if !should_ignore {

src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ fn main() {
317317
#[test]
318318
fn mismatched_types_issue_15883() {
319319
// Check we don't panic.
320-
check_diagnostics_no_bails(
320+
cov_mark::check!(validate_match_bailed_out);
321+
check_diagnostics(
321322
r#"
322323
//- minicore: option
323324
fn main() {

0 commit comments

Comments
 (0)