Skip to content

Commit d21a978

Browse files
committed
Auto merge of rust-lang#17078 - Veykril:diags-perf, r=Veykril
internal: Improve diagnostics performance
2 parents 76141f0 + 5a650d4 commit d21a978

File tree

18 files changed

+176
-158
lines changed

18 files changed

+176
-158
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

+10-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
2727
type_ref::TypeRef,
2828
visibility::RawVisibility,
29-
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId,
29+
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
3030
};
3131

3232
/// Note that we use `StructData` for unions as well!
@@ -378,6 +378,15 @@ impl VariantData {
378378
VariantData::Unit => StructKind::Unit,
379379
}
380380
}
381+
382+
#[allow(clippy::self_named_constructors)]
383+
pub(crate) fn variant_data(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> {
384+
match id {
385+
VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
386+
VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(),
387+
VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
388+
}
389+
}
381390
}
382391

383392
#[derive(Debug, Copy, Clone, PartialEq, Eq)]

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
attr::{Attrs, AttrsWithOwner},
1313
body::{scope::ExprScopes, Body, BodySourceMap},
1414
data::{
15-
adt::{EnumData, EnumVariantData, StructData},
15+
adt::{EnumData, EnumVariantData, StructData, VariantData},
1616
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
1717
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
1818
},
@@ -127,6 +127,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
127127
id: EnumVariantId,
128128
) -> (Arc<EnumVariantData>, DefDiagnostics);
129129

130+
#[salsa::transparent]
131+
#[salsa::invoke(VariantData::variant_data)]
132+
fn variant_data(&self, id: VariantId) -> Arc<VariantData>;
130133
#[salsa::transparent]
131134
#[salsa::invoke(ImplData::impl_data_query)]
132135
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;

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

+52-41
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use hir_def::{ItemContainerId, Lookup};
1111
use hir_expand::name;
1212
use itertools::Itertools;
1313
use rustc_hash::FxHashSet;
14+
use rustc_pattern_analysis::constructor::Constructor;
1415
use syntax::{ast, AstNode};
1516
use tracing::debug;
1617
use triomphe::Arc;
@@ -190,45 +191,45 @@ impl ExprValidator {
190191
let pattern_arena = Arena::new();
191192
let mut m_arms = Vec::with_capacity(arms.len());
192193
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.
193196
for arm in arms {
194-
if let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) {
195-
// We only include patterns whose type matches the type
196-
// of the scrutinee expression. If we had an InvalidMatchArmPattern
197-
// diagnostic or similar we could raise that in an else
198-
// block here.
199-
//
200-
// When comparing the types, we also have to consider that rustc
201-
// will automatically de-reference the scrutinee expression type if
202-
// necessary.
203-
//
204-
// FIXME we should use the type checker for this.
205-
if (pat_ty == scrut_ty
206-
|| scrut_ty
207-
.as_reference()
208-
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
209-
.unwrap_or(false))
210-
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
211-
{
212-
// If we had a NotUsefulMatchArm diagnostic, we could
213-
// check the usefulness of each pattern as we added it
214-
// to the matrix here.
215-
let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
216-
let m_arm = pat_analysis::MatchArm {
217-
pat: pattern_arena.alloc(pat),
218-
has_guard: arm.guard.is_some(),
219-
arm_data: (),
220-
};
221-
m_arms.push(m_arm);
222-
if !has_lowering_errors {
223-
continue;
224-
}
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;
225230
}
226231
}
227-
228-
// If we can't resolve the type of a pattern, or the pattern type doesn't
229-
// fit the match expression, we skip this diagnostic. Skipping the entire
230-
// diagnostic rather than just not including this match arm is preferred
231-
// to avoid the chance of false positives.
232+
// If the pattern type doesn't fit the match expression, we skip this diagnostic.
232233
cov_mark::hit!(validate_match_bailed_out);
233234
return;
234235
}
@@ -266,15 +267,17 @@ impl ExprValidator {
266267

267268
let mut have_errors = false;
268269
let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
270+
271+
// optimization, wildcard trivially hold
272+
if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
273+
continue;
274+
}
275+
269276
let match_arm = rustc_pattern_analysis::MatchArm {
270277
pat: pattern_arena.alloc(deconstructed_pat),
271278
has_guard: false,
272279
arm_data: (),
273280
};
274-
if have_errors {
275-
continue;
276-
}
277-
278281
let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) {
279282
Ok(v) => v,
280283
Err(e) => {
@@ -531,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
531534
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
532535
match infer.type_mismatch_for_pat(pat) {
533536
Some(_) => *has_type_mismatches = true,
537+
None if *has_type_mismatches => (),
534538
None => {
535-
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))
536547
}
537548
}
538549
}

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

+23-30
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Interface with `rustc_pattern_analysis`.
22
33
use std::fmt;
4-
use tracing::debug;
54

65
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
6+
use once_cell::unsync::Lazy;
77
use rustc_hash::FxHashMap;
88
use rustc_pattern_analysis::{
99
constructor::{Constructor, ConstructorSet, VariantVisibility},
@@ -91,20 +91,13 @@ impl<'p> MatchCheckCtx<'p> {
9191
}
9292

9393
fn is_uninhabited(&self, ty: &Ty) -> bool {
94-
is_ty_uninhabited_from(ty, self.module, self.db)
94+
is_ty_uninhabited_from(self.db, ty, self.module)
9595
}
9696

97-
/// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
98-
fn is_foreign_non_exhaustive_enum(&self, ty: &Ty) -> bool {
99-
match ty.as_adt() {
100-
Some((adt @ hir_def::AdtId::EnumId(_), _)) => {
101-
let has_non_exhaustive_attr =
102-
self.db.attrs(adt.into()).by_key("non_exhaustive").exists();
103-
let is_local = adt.module(self.db.upcast()).krate() == self.module.krate();
104-
has_non_exhaustive_attr && !is_local
105-
}
106-
_ => false,
107-
}
97+
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
98+
fn is_foreign_non_exhaustive(&self, adt: hir_def::AdtId) -> bool {
99+
let is_local = adt.krate(self.db.upcast()) == self.module.krate();
100+
!is_local && self.db.attrs(adt.into()).by_key("non_exhaustive").exists()
108101
}
109102

110103
fn variant_id_for_adt(
@@ -376,24 +369,21 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
376369
single(subst_ty)
377370
} else {
378371
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
379-
let (adt, _) = ty.as_adt().unwrap();
380372

381-
let adt_is_local =
382-
variant.module(self.db.upcast()).krate() == self.module.krate();
383373
// Whether we must not match the fields of this variant exhaustively.
384-
let is_non_exhaustive =
385-
self.db.attrs(variant.into()).by_key("non_exhaustive").exists()
386-
&& !adt_is_local;
387-
let visibilities = self.db.field_visibilities(variant);
374+
let is_non_exhaustive = Lazy::new(|| self.is_foreign_non_exhaustive(adt));
375+
let visibilities = Lazy::new(|| self.db.field_visibilities(variant));
388376

389377
self.list_variant_fields(ty, variant)
390378
.map(move |(fid, ty)| {
391-
let is_visible = matches!(adt, hir_def::AdtId::EnumId(..))
392-
|| visibilities[fid]
393-
.is_visible_from(self.db.upcast(), self.module);
379+
let is_visible = || {
380+
matches!(adt, hir_def::AdtId::EnumId(..))
381+
|| visibilities[fid]
382+
.is_visible_from(self.db.upcast(), self.module)
383+
};
394384
let is_uninhabited = self.is_uninhabited(&ty);
395385
let private_uninhabited =
396-
is_uninhabited && (!is_visible || is_non_exhaustive);
386+
is_uninhabited && (!is_visible() || *is_non_exhaustive);
397387
(ty, PrivateUninhabitedField(private_uninhabited))
398388
})
399389
.collect()
@@ -445,17 +435,20 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
445435
TyKind::Scalar(Scalar::Char) => unhandled(),
446436
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
447437
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
448-
TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
449-
let enum_data = cx.db.enum_data(*enum_id);
450-
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty);
438+
&TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
439+
let enum_data = cx.db.enum_data(enum_id);
440+
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
451441

452442
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
453443
ConstructorSet::NoConstructors
454444
} else {
455-
let mut variants = FxHashMap::default();
445+
let mut variants = FxHashMap::with_capacity_and_hasher(
446+
enum_data.variants.len(),
447+
Default::default(),
448+
);
456449
for (i, &(variant, _)) in enum_data.variants.iter().enumerate() {
457450
let is_uninhabited =
458-
is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
451+
is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module);
459452
let visibility = if is_uninhabited {
460453
VariantVisibility::Empty
461454
} else {
@@ -506,7 +499,7 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
506499
}
507500

508501
fn bug(&self, fmt: fmt::Arguments<'_>) {
509-
debug!("{}", fmt)
502+
never!("{}", fmt)
510503
}
511504

512505
fn complexity_exceeded(&self) -> Result<(), Self::Error> {

0 commit comments

Comments
 (0)