Skip to content

Commit a51267c

Browse files
committed
Allocate traits in scope upfront when type checking instead of recollecting them everytime
1 parent a8606e5 commit a51267c

File tree

4 files changed

+66
-50
lines changed

4 files changed

+66
-50
lines changed

crates/hir-def/src/resolver.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,15 @@ impl Resolver {
449449
traits
450450
}
451451

452+
pub fn traits_in_scope_from_block_scopes(&self) -> impl Iterator<Item = TraitId> + '_ {
453+
self.scopes()
454+
.filter_map(|scope| match scope {
455+
Scope::BlockScope(m) => Some(m.def_map[m.module_id].scope.traits()),
456+
_ => None,
457+
})
458+
.flatten()
459+
}
460+
452461
pub fn module(&self) -> ModuleId {
453462
let (def_map, local_id) = self.item_scope();
454463
def_map.module_id(local_id)

crates/hir-ty/src/infer.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use hir_def::{
3333
};
3434
use hir_expand::name::{name, Name};
3535
use la_arena::ArenaMap;
36-
use rustc_hash::FxHashMap;
36+
use rustc_hash::{FxHashMap, FxHashSet};
3737
use stdx::always;
3838

3939
use crate::{
@@ -423,6 +423,8 @@ pub(crate) struct InferenceContext<'a> {
423423
pub(crate) resolver: Resolver,
424424
table: unify::InferenceTable<'a>,
425425
trait_env: Arc<TraitEnvironment>,
426+
/// The traits in scope, disregarding block modules. This is used for caching purposes.
427+
traits_in_scope: FxHashSet<TraitId>,
426428
pub(crate) result: InferenceResult,
427429
/// The return type of the function being inferred, the closure or async block if we're
428430
/// currently within one.
@@ -505,6 +507,7 @@ impl<'a> InferenceContext<'a> {
505507
db,
506508
owner,
507509
body,
510+
traits_in_scope: resolver.traits_in_scope(db.upcast()),
508511
resolver,
509512
diverges: Diverges::Maybe,
510513
breakables: Vec::new(),
@@ -1056,6 +1059,15 @@ impl<'a> InferenceContext<'a> {
10561059
let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?;
10571060
Some(struct_.into())
10581061
}
1062+
1063+
fn get_traits_in_scope(&self) -> Either<FxHashSet<TraitId>, &FxHashSet<TraitId>> {
1064+
let mut b_traits = self.resolver.traits_in_scope_from_block_scopes().peekable();
1065+
if b_traits.peek().is_some() {
1066+
Either::Left(self.traits_in_scope.iter().copied().chain(b_traits).collect())
1067+
} else {
1068+
Either::Right(&self.traits_in_scope)
1069+
}
1070+
}
10591071
}
10601072

10611073
/// When inferring an expression, we propagate downward whatever type hint we

crates/hir-ty/src/infer/expr.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,14 +1349,14 @@ impl<'a> InferenceContext<'a> {
13491349
None => {
13501350
// no field found,
13511351
let method_with_same_name_exists = {
1352-
let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
1353-
let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
1352+
self.get_traits_in_scope();
13541353

1354+
let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
13551355
method_resolution::lookup_method(
13561356
self.db,
13571357
&canonicalized_receiver.value,
13581358
self.trait_env.clone(),
1359-
&traits_in_scope,
1359+
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
13601360
VisibleFromModule::Filter(self.resolver.module()),
13611361
name,
13621362
)
@@ -1385,13 +1385,11 @@ impl<'a> InferenceContext<'a> {
13851385
let receiver_ty = self.infer_expr(receiver, &Expectation::none());
13861386
let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
13871387

1388-
let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
1389-
13901388
let resolved = method_resolution::lookup_method(
13911389
self.db,
13921390
&canonicalized_receiver.value,
13931391
self.trait_env.clone(),
1394-
&traits_in_scope,
1392+
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
13951393
VisibleFromModule::Filter(self.resolver.module()),
13961394
method_name,
13971395
);

crates/hir-ty/src/infer/path.rs

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ impl<'a> InferenceContext<'a> {
205205
Some((def, Some(trait_ref.substitution)))
206206
}
207207

208+
// FIXME: Change sig to -> Option<(ValueNs, Substitution)>, subs aren't optional from here anymore
208209
fn resolve_ty_assoc_item(
209210
&mut self,
210211
ty: Ty,
@@ -220,70 +221,66 @@ impl<'a> InferenceContext<'a> {
220221
}
221222

222223
let canonical_ty = self.canonicalize(ty.clone());
223-
let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
224224

225225
let mut not_visible = None;
226226
let res = method_resolution::iterate_method_candidates(
227227
&canonical_ty.value,
228228
self.db,
229229
self.table.trait_env.clone(),
230-
&traits_in_scope,
230+
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
231231
VisibleFromModule::Filter(self.resolver.module()),
232232
Some(name),
233233
method_resolution::LookupMode::Path,
234234
|_ty, item, visible| {
235-
let (def, container) = match item {
236-
AssocItemId::FunctionId(f) => {
237-
(ValueNs::FunctionId(f), f.lookup(self.db.upcast()).container)
238-
}
239-
AssocItemId::ConstId(c) => {
240-
(ValueNs::ConstId(c), c.lookup(self.db.upcast()).container)
241-
}
242-
AssocItemId::TypeAliasId(_) => unreachable!(),
243-
};
244-
let substs = match container {
245-
ItemContainerId::ImplId(impl_id) => {
246-
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
247-
.fill_with_inference_vars(&mut self.table)
248-
.build();
249-
let impl_self_ty =
250-
self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
251-
self.unify(&impl_self_ty, &ty);
252-
impl_substs
253-
}
254-
ItemContainerId::TraitId(trait_) => {
255-
// we're picking this method
256-
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
257-
.push(ty.clone())
258-
.fill_with_inference_vars(&mut self.table)
259-
.build();
260-
self.push_obligation(trait_ref.clone().cast(Interner));
261-
trait_ref.substitution
262-
}
263-
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
264-
never!("assoc item contained in module/extern block");
265-
return None;
266-
}
267-
};
268-
269235
if visible {
270-
Some((def, item, Some(substs), true))
236+
Some((item, true))
271237
} else {
272238
if not_visible.is_none() {
273-
not_visible = Some((def, item, Some(substs), false));
239+
not_visible = Some((item, false));
274240
}
275241
None
276242
}
277243
},
278244
);
279245
let res = res.or(not_visible);
280-
if let Some((_, item, Some(ref substs), visible)) = res {
281-
self.write_assoc_resolution(id, item, substs.clone());
282-
if !visible {
283-
self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item })
246+
let (item, visible) = res?;
247+
248+
let (def, container) = match item {
249+
AssocItemId::FunctionId(f) => {
250+
(ValueNs::FunctionId(f), f.lookup(self.db.upcast()).container)
284251
}
252+
AssocItemId::ConstId(c) => (ValueNs::ConstId(c), c.lookup(self.db.upcast()).container),
253+
AssocItemId::TypeAliasId(_) => unreachable!(),
254+
};
255+
let substs = match container {
256+
ItemContainerId::ImplId(impl_id) => {
257+
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
258+
.fill_with_inference_vars(&mut self.table)
259+
.build();
260+
let impl_self_ty = self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
261+
self.unify(&impl_self_ty, &ty);
262+
impl_substs
263+
}
264+
ItemContainerId::TraitId(trait_) => {
265+
// we're picking this method
266+
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
267+
.push(ty.clone())
268+
.fill_with_inference_vars(&mut self.table)
269+
.build();
270+
self.push_obligation(trait_ref.clone().cast(Interner));
271+
trait_ref.substitution
272+
}
273+
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
274+
never!("assoc item contained in module/extern block");
275+
return None;
276+
}
277+
};
278+
279+
self.write_assoc_resolution(id, item, substs.clone());
280+
if !visible {
281+
self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem { id, item });
285282
}
286-
res.map(|(def, _, substs, _)| (def, substs))
283+
Some((def, Some(substs)))
287284
}
288285

289286
fn resolve_enum_variant_on_ty(

0 commit comments

Comments
 (0)