Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a360fab

Browse files
committed
Auto merge of rust-lang#14261 - Veykril:ty-perf, r=Veykril
internal: Re-use the resolver in `InferenceContext` instead of rebuilding it whenever needed This reduced inference time on my local build by roughly ~1 sec (out of like 60)
2 parents 900efbe + d8b1ec6 commit a360fab

File tree

7 files changed

+248
-143
lines changed

7 files changed

+248
-143
lines changed

crates/hir-def/src/body/scope.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl ExprScopes {
6666
self.scopes[scope].label.clone()
6767
}
6868

69+
/// Returns the scopes in ascending order.
6970
pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
7071
std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
7172
}

crates/hir-def/src/resolver.rs

Lines changed: 162 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Name resolution façade.
2-
use std::{hash::BuildHasherDefault, sync::Arc};
2+
use std::{fmt, hash::BuildHasherDefault, sync::Arc};
33

44
use base_db::CrateId;
55
use hir_expand::name::{name, Name};
@@ -36,19 +36,34 @@ pub struct Resolver {
3636
module_scope: ModuleItemMap,
3737
}
3838

39-
#[derive(Debug, Clone)]
39+
#[derive(Clone)]
4040
struct ModuleItemMap {
4141
def_map: Arc<DefMap>,
4242
module_id: LocalModuleId,
4343
}
4444

45-
#[derive(Debug, Clone)]
45+
impl fmt::Debug for ModuleItemMap {
46+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47+
f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish()
48+
}
49+
}
50+
51+
#[derive(Clone)]
4652
struct ExprScope {
4753
owner: DefWithBodyId,
4854
expr_scopes: Arc<ExprScopes>,
4955
scope_id: ScopeId,
5056
}
5157

58+
impl fmt::Debug for ExprScope {
59+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60+
f.debug_struct("ExprScope")
61+
.field("owner", &self.owner)
62+
.field("scope_id", &self.scope_id)
63+
.finish()
64+
}
65+
}
66+
5267
#[derive(Debug, Clone)]
5368
enum Scope {
5469
/// All the items and imported names of a module
@@ -240,55 +255,67 @@ impl Resolver {
240255
return self.module_scope.resolve_path_in_value_ns(db, path);
241256
}
242257

243-
for scope in self.scopes() {
244-
match scope {
245-
Scope::ExprScope(_) if n_segments > 1 => continue,
246-
Scope::ExprScope(scope) => {
247-
let entry = scope
248-
.expr_scopes
249-
.entries(scope.scope_id)
250-
.iter()
251-
.find(|entry| entry.name() == first_name);
252-
253-
if let Some(e) = entry {
254-
return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
258+
if n_segments <= 1 {
259+
for scope in self.scopes() {
260+
match scope {
261+
Scope::ExprScope(scope) => {
262+
let entry = scope
263+
.expr_scopes
264+
.entries(scope.scope_id)
265+
.iter()
266+
.find(|entry| entry.name() == first_name);
267+
268+
if let Some(e) = entry {
269+
return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(
270+
e.pat(),
271+
)));
272+
}
255273
}
256-
}
257-
Scope::GenericParams { params, def } if n_segments > 1 => {
258-
if let Some(id) = params.find_type_by_name(first_name, *def) {
259-
let ty = TypeNs::GenericParam(id);
260-
return Some(ResolveValueResult::Partial(ty, 1));
274+
Scope::GenericParams { params, def } => {
275+
if let Some(id) = params.find_const_by_name(first_name, *def) {
276+
let val = ValueNs::GenericParam(id);
277+
return Some(ResolveValueResult::ValueNs(val));
278+
}
261279
}
262-
}
263-
Scope::GenericParams { .. } if n_segments != 1 => continue,
264-
Scope::GenericParams { params, def } => {
265-
if let Some(id) = params.find_const_by_name(first_name, *def) {
266-
let val = ValueNs::GenericParam(id);
267-
return Some(ResolveValueResult::ValueNs(val));
280+
&Scope::ImplDefScope(impl_) => {
281+
if first_name == &name![Self] {
282+
return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)));
283+
}
268284
}
269-
}
270-
271-
&Scope::ImplDefScope(impl_) => {
272-
if first_name == &name![Self] {
273-
return Some(if n_segments > 1 {
274-
ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
275-
} else {
276-
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
277-
});
285+
// bare `Self` doesn't work in the value namespace in a struct/enum definition
286+
Scope::AdtScope(_) => continue,
287+
Scope::BlockScope(m) => {
288+
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
289+
return Some(def);
290+
}
278291
}
279292
}
280-
// bare `Self` doesn't work in the value namespace in a struct/enum definition
281-
Scope::AdtScope(_) if n_segments == 1 => continue,
282-
Scope::AdtScope(adt) => {
283-
if first_name == &name![Self] {
284-
let ty = TypeNs::AdtSelfType(*adt);
285-
return Some(ResolveValueResult::Partial(ty, 1));
293+
}
294+
} else {
295+
for scope in self.scopes() {
296+
match scope {
297+
Scope::ExprScope(_) => continue,
298+
Scope::GenericParams { params, def } => {
299+
if let Some(id) = params.find_type_by_name(first_name, *def) {
300+
let ty = TypeNs::GenericParam(id);
301+
return Some(ResolveValueResult::Partial(ty, 1));
302+
}
286303
}
287-
}
288-
289-
Scope::BlockScope(m) => {
290-
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
291-
return Some(def);
304+
&Scope::ImplDefScope(impl_) => {
305+
if first_name == &name![Self] {
306+
return Some(ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1));
307+
}
308+
}
309+
Scope::AdtScope(adt) => {
310+
if first_name == &name![Self] {
311+
let ty = TypeNs::AdtSelfType(*adt);
312+
return Some(ResolveValueResult::Partial(ty, 1));
313+
}
314+
}
315+
Scope::BlockScope(m) => {
316+
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
317+
return Some(def);
318+
}
292319
}
293320
}
294321
}
@@ -301,8 +328,8 @@ impl Resolver {
301328
// If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
302329
// to resolving to the primitive type, to allow this to still work in the presence of
303330
// `use core::u16;`.
304-
if path.kind == PathKind::Plain && path.segments().len() > 1 {
305-
if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
331+
if path.kind == PathKind::Plain && n_segments > 1 {
332+
if let Some(builtin) = BuiltinType::by_name(first_name) {
306333
return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
307334
}
308335
}
@@ -434,6 +461,15 @@ impl Resolver {
434461
traits
435462
}
436463

464+
pub fn traits_in_scope_from_block_scopes(&self) -> impl Iterator<Item = TraitId> + '_ {
465+
self.scopes()
466+
.filter_map(|scope| match scope {
467+
Scope::BlockScope(m) => Some(m.def_map[m.module_id].scope.traits()),
468+
_ => None,
469+
})
470+
.flatten()
471+
}
472+
437473
pub fn module(&self) -> ModuleId {
438474
let (def_map, local_id) = self.item_scope();
439475
def_map.module_id(local_id)
@@ -478,8 +514,72 @@ impl Resolver {
478514
_ => None,
479515
})
480516
}
517+
/// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver
518+
#[must_use]
519+
pub fn update_to_inner_scope(
520+
&mut self,
521+
db: &dyn DefDatabase,
522+
owner: DefWithBodyId,
523+
expr_id: ExprId,
524+
) -> UpdateGuard {
525+
#[inline(always)]
526+
fn append_expr_scope(
527+
db: &dyn DefDatabase,
528+
resolver: &mut Resolver,
529+
owner: DefWithBodyId,
530+
expr_scopes: &Arc<ExprScopes>,
531+
scope_id: ScopeId,
532+
) {
533+
resolver.scopes.push(Scope::ExprScope(ExprScope {
534+
owner,
535+
expr_scopes: expr_scopes.clone(),
536+
scope_id,
537+
}));
538+
if let Some(block) = expr_scopes.block(scope_id) {
539+
if let Some(def_map) = db.block_def_map(block) {
540+
let root = def_map.root();
541+
resolver
542+
.scopes
543+
.push(Scope::BlockScope(ModuleItemMap { def_map, module_id: root }));
544+
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
545+
// already traverses all parents, so this is O(n²). I think we could only store the
546+
// innermost module scope instead?
547+
}
548+
}
549+
}
550+
551+
let start = self.scopes.len();
552+
let innermost_scope = self.scopes().next();
553+
match innermost_scope {
554+
Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => {
555+
let expr_scopes = expr_scopes.clone();
556+
let scope_chain = expr_scopes
557+
.scope_chain(expr_scopes.scope_for(expr_id))
558+
.take_while(|&it| it != scope_id);
559+
for scope_id in scope_chain {
560+
append_expr_scope(db, self, owner, &expr_scopes, scope_id);
561+
}
562+
}
563+
_ => {
564+
let expr_scopes = db.expr_scopes(owner);
565+
let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id));
566+
567+
for scope_id in scope_chain {
568+
append_expr_scope(db, self, owner, &expr_scopes, scope_id);
569+
}
570+
}
571+
}
572+
self.scopes[start..].reverse();
573+
UpdateGuard(start)
574+
}
575+
576+
pub fn reset_to_guard(&mut self, UpdateGuard(start): UpdateGuard) {
577+
self.scopes.truncate(start);
578+
}
481579
}
482580

581+
pub struct UpdateGuard(usize);
582+
483583
impl Resolver {
484584
fn scopes(&self) -> impl Iterator<Item = &Scope> {
485585
self.scopes.iter().rev()
@@ -576,19 +676,30 @@ impl Scope {
576676
}
577677
}
578678

579-
// needs arbitrary_self_types to be a method... or maybe move to the def?
580679
pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
680+
let r = owner.resolver(db);
581681
let scopes = db.expr_scopes(owner);
582-
resolver_for_scope(db, owner, scopes.scope_for(expr_id))
682+
let scope_id = scopes.scope_for(expr_id);
683+
resolver_for_scope_(db, scopes, scope_id, r, owner)
583684
}
584685

585686
pub fn resolver_for_scope(
586687
db: &dyn DefDatabase,
587688
owner: DefWithBodyId,
588689
scope_id: Option<ScopeId>,
589690
) -> Resolver {
590-
let mut r = owner.resolver(db);
691+
let r = owner.resolver(db);
591692
let scopes = db.expr_scopes(owner);
693+
resolver_for_scope_(db, scopes, scope_id, r, owner)
694+
}
695+
696+
fn resolver_for_scope_(
697+
db: &dyn DefDatabase,
698+
scopes: Arc<ExprScopes>,
699+
scope_id: Option<ScopeId>,
700+
mut r: Resolver,
701+
owner: DefWithBodyId,
702+
) -> Resolver {
592703
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
593704
r.scopes.reserve(scope_chain.len());
594705

crates/hir-ty/src/infer.rs

Lines changed: 15 additions & 5 deletions
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(),
@@ -706,7 +709,6 @@ impl<'a> InferenceContext<'a> {
706709
}
707710

708711
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
709-
// FIXME use right resolver for block
710712
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
711713
let ty = ctx.lower_ty(type_ref);
712714
let ty = self.insert_type_vars(ty);
@@ -822,12 +824,11 @@ impl<'a> InferenceContext<'a> {
822824
Some(path) => path,
823825
None => return (self.err_ty(), None),
824826
};
825-
let resolver = &self.resolver;
826827
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
827828
// FIXME: this should resolve assoc items as well, see this example:
828829
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
829830
let (resolution, unresolved) = if value_ns {
830-
match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
831+
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
831832
Some(ResolveValueResult::ValueNs(value)) => match value {
832833
ValueNs::EnumVariantId(var) => {
833834
let substs = ctx.substs_from_path(path, var.into(), true);
@@ -848,7 +849,7 @@ impl<'a> InferenceContext<'a> {
848849
None => return (self.err_ty(), None),
849850
}
850851
} else {
851-
match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
852+
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
852853
Some(it) => it,
853854
None => return (self.err_ty(), None),
854855
}
@@ -1058,6 +1059,15 @@ impl<'a> InferenceContext<'a> {
10581059
let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?;
10591060
Some(struct_.into())
10601061
}
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+
}
10611071
}
10621072

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

0 commit comments

Comments
 (0)