Skip to content

Commit 90cfa80

Browse files
committed
Auto merge of #17078 - Veykril:diags-perf, r=Veykril
internal: Improve diagnostics performance
2 parents b223860 + 531a270 commit 90cfa80

18 files changed

Lines changed: 176 additions & 158 deletions

File tree

‎crates/base-db/src/lib.rs‎

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

4646
pubconstDEFAULT_FILE_TEXT_LRU_CAP:usize = 16;
4747
pubconstDEFAULT_PARSE_LRU_CAP:usize = 128;
48-
pubconstDEFAULT_BORROWCK_LRU_CAP:usize = 1024;
48+
pubconstDEFAULT_BORROWCK_LRU_CAP:usize = 2024;
4949

5050
pubtraitFileLoader{
5151
/// Text of the file.

‎crates/hir-def/src/data.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ pub struct ConstData {
510510
pubtype_ref:Interned<TypeRef>,
511511
pubvisibility:RawVisibility,
512512
pubrustc_allow_incoherent_impl:bool,
513+
pubhas_body:bool,
513514
}
514515

515516
implConstData{
@@ -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
}

‎crates/hir-def/src/data/adt.rs‎

Lines changed: 10 additions & 1 deletion
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)fnvariant_data(db:&dynDefDatabase,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)]

‎crates/hir-def/src/db.rs‎

Lines changed: 4 additions & 1 deletion
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+
fnvariant_data(&self,id:VariantId) -> Arc<VariantData>;
130133
#[salsa::transparent]
131134
#[salsa::invoke(ImplData::impl_data_query)]
132135
fnimpl_data(&self,e:ImplId) -> Arc<ImplData>;

‎crates/hir-def/src/item_tree.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ pub struct Const {
716716
pubvisibility:RawVisibilityId,
717717
pubtype_ref:Interned<TypeRef>,
718718
pubast_id:FileAstId<ast::Const>,
719+
pubhas_body:bool,
719720
}
720721

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

‎crates/hir-def/src/item_tree/lower.rs‎

Lines changed: 1 addition & 1 deletion
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

‎crates/hir-def/src/item_tree/pretty.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ impl Printer<'_> {
357357
wln!(self,"}}");
358358
}
359359
ModItem::Const(it) => {
360-
letConst{ name, visibility, type_ref, ast_id } = &self.tree[it];
360+
letConst{ 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 ");

‎crates/hir-ty/src/diagnostics/decl_check.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod allow {
4343
}
4444

4545
pubfnincorrect_case(db:&dynHirDatabase,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
letmut validator = DeclValidator::new(db);
4848
validator.validate_item(owner);
4949
validator.sink

‎crates/hir-ty/src/diagnostics/expr.rs‎

Lines changed: 52 additions & 41 deletions
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
letmut m_arms = Vec::with_capacity(arms.len());
192193
letmut 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-
ifletSome(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+
letSome(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
letmut 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
fnwalk(pat:PatId,body:&Body,infer:&InferenceResult,has_type_mismatches:&mutbool){
532535
match infer.type_mismatch_for_pat(pat){
533536
Some(_) => *has_type_mismatches = true,
537+
Noneif*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+
ifletPat::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
}

‎crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs‎

Lines changed: 23 additions & 30 deletions
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
fnis_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-
fnis_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+
fnis_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
fnvariant_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-
letmut variants = FxHashMap::default();
445+
letmut 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
fnbug(&self,fmt: fmt::Arguments<'_>){
509-
debug!("{}", fmt)
502+
never!("{}", fmt)
510503
}
511504

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

0 commit comments

Comments
 (0)