From 7ec62ea5e686dcb6de5d3fcc413f32af9d1c9cb5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jan 2020 14:11:07 +0100 Subject: Push resolver up --- crates/ra_hir_ty/src/method_resolution.rs | 72 ++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 55435e6ea..e43fadf20 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -12,7 +12,7 @@ use hir_def::{ use hir_expand::name::Name; use ra_db::CrateId; use ra_prof::profile; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use super::Substs; use crate::{ @@ -177,6 +177,9 @@ pub fn iterate_method_candidates( mode: LookupMode, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { + let traits_in_scope = resolver.traits_in_scope(db); + let krate = resolver.krate()?; + let env = TraitEnvironment::lower(db, resolver); match mode { LookupMode::MethodCall => { // For method calls, rust first does any number of autoderef, and then one @@ -209,7 +212,9 @@ pub fn iterate_method_candidates( if let Some(result) = iterate_method_candidates_with_autoref( &deref_chain[i..], db, - resolver, + env.clone(), + krate, + &traits_in_scope, name, &mut callback, ) { @@ -220,7 +225,15 @@ pub fn iterate_method_candidates( } LookupMode::Path => { // No autoderef for path lookups - iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback) + iterate_method_candidates_for_self_ty( + &ty, + db, + env, + krate, + &traits_in_scope, + name, + &mut callback, + ) } } } @@ -228,7 +241,9 @@ pub fn iterate_method_candidates( fn iterate_method_candidates_with_autoref( deref_chain: &[Canonical], db: &impl HirDatabase, - resolver: &Resolver, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { @@ -236,7 +251,9 @@ fn iterate_method_candidates_with_autoref( &deref_chain[0], &deref_chain[1..], db, - resolver, + env.clone(), + krate, + &traits_in_scope, name, &mut callback, ) { @@ -250,7 +267,9 @@ fn iterate_method_candidates_with_autoref( &refed, deref_chain, db, - resolver, + env.clone(), + krate, + &traits_in_scope, name, &mut callback, ) { @@ -264,7 +283,9 @@ fn iterate_method_candidates_with_autoref( &ref_muted, deref_chain, db, - resolver, + env.clone(), + krate, + &traits_in_scope, name, &mut callback, ) { @@ -277,14 +298,15 @@ fn iterate_method_candidates_by_receiver( receiver_ty: &Canonical, rest_of_deref_chain: &[Canonical], db: &impl HirDatabase, - resolver: &Resolver, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that. - let krate = resolver.krate()?; for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { if let Some(result) = iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) @@ -296,7 +318,9 @@ fn iterate_method_candidates_by_receiver( if let Some(result) = iterate_trait_method_candidates( self_ty, db, - resolver, + env.clone(), + krate, + &traits_in_scope, name, Some(receiver_ty), &mut callback, @@ -310,17 +334,25 @@ fn iterate_method_candidates_by_receiver( fn iterate_method_candidates_for_self_ty( self_ty: &Canonical, db: &impl HirDatabase, - resolver: &Resolver, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - let krate = resolver.krate()?; if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { return Some(result); } - if let Some(result) = - iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback) - { + if let Some(result) = iterate_trait_method_candidates( + self_ty, + db, + env, + krate, + traits_in_scope, + name, + None, + &mut callback, + ) { return Some(result); } None @@ -329,14 +361,13 @@ fn iterate_method_candidates_for_self_ty( fn iterate_trait_method_candidates( self_ty: &Canonical, db: &impl HirDatabase, - resolver: &Resolver, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: Option<&Name>, receiver_ty: Option<&Canonical>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - let krate = resolver.krate()?; - // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) - let env = TraitEnvironment::lower(db, resolver); // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope let inherent_trait = self_ty.value.inherent_trait().into_iter(); // if we have `T: Trait` in the param env, the trait doesn't need to be in scope @@ -344,8 +375,7 @@ fn iterate_trait_method_candidates( .trait_predicates_for_self_ty(&self_ty.value) .map(|tr| tr.trait_) .flat_map(|t| all_super_traits(db, t)); - let traits = - inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db).into_iter()); + let traits = inherent_trait.chain(traits_from_env).chain(traits_in_scope.iter().copied()); 'traits: for t in traits { let data = db.trait_data(t); -- cgit v1.2.3 From 21c5fd8b1b8f9536449325738baea1e48efdefe0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jan 2020 14:20:33 +0100 Subject: Push resolver further up --- crates/ra_hir/src/source_analyzer.rs | 18 ++++++++++++-- crates/ra_hir_ty/src/infer/expr.rs | 19 +++++++++----- crates/ra_hir_ty/src/infer/path.rs | 9 +++++-- crates/ra_hir_ty/src/method_resolution.rs | 41 ++++++++++++++++++------------- 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 3df48842d..5707a5696 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -358,10 +358,17 @@ impl SourceAnalyzer { // FIXME check that? // FIXME replace Unknown by bound vars here let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 }; + + let env = TraitEnvironment::lower(db, &self.resolver); + let krate = self.resolver.krate()?; + let traits_in_scope = self.resolver.traits_in_scope(db); + method_resolution::iterate_method_candidates( &canonical, db, - &self.resolver, + env, + krate, + &traits_in_scope, name, method_resolution::LookupMode::MethodCall, |ty, it| match it { @@ -382,10 +389,17 @@ impl SourceAnalyzer { // FIXME check that? // FIXME replace Unknown by bound vars here let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 }; + + let env = TraitEnvironment::lower(db, &self.resolver); + let krate = self.resolver.krate()?; + let traits_in_scope = self.resolver.traits_in_scope(db); + method_resolution::iterate_method_candidates( &canonical, db, - &self.resolver, + env, + krate, + &traits_in_scope, name, method_resolution::LookupMode::Path, |ty, it| callback(ty, it.into()), diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 3af05394c..d6a17e469 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -569,12 +569,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ) -> Ty { let receiver_ty = self.infer_expr(receiver, &Expectation::none()); let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); - let resolved = method_resolution::lookup_method( - &canonicalized_receiver.value, - self.db, - method_name, - &self.resolver, - ); + + let traits_in_scope = self.resolver.traits_in_scope(self.db); + + let resolved = self.resolver.krate().and_then(|krate| { + method_resolution::lookup_method( + &canonicalized_receiver.value, + self.db, + self.trait_env.clone(), + krate, + &traits_in_scope, + method_name, + ) + }); let (derefed_receiver_ty, method_ty, def_generics) = match resolved { Some((ty, func)) => { let ty = canonicalized_receiver.decanonicalize_ty(ty); diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index ffd358367..2c1d4831d 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -11,7 +11,7 @@ use hir_expand::name::Name; use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; -use super::{ExprOrPatId, InferenceContext, TraitRef}; +use super::{ExprOrPatId, InferenceContext, TraitEnvironment, TraitRef}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { pub(super) fn infer_path( @@ -193,11 +193,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); + let env = TraitEnvironment::lower(self.db, &self.resolver); + let krate = self.resolver.krate()?; + let traits_in_scope = self.resolver.traits_in_scope(self.db); method_resolution::iterate_method_candidates( &canonical_ty.value, self.db, - &self.resolver.clone(), + env, + krate, + &traits_in_scope, Some(name), method_resolution::LookupMode::Path, move |_ty, item| { diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e43fadf20..5bacbbd7c 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ - lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId, - AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, + lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId, + HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; @@ -144,14 +144,24 @@ impl Ty { pub(crate) fn lookup_method( ty: &Canonical, db: &impl HirDatabase, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: &Name, - resolver: &Resolver, ) -> Option<(Ty, FunctionId)> { - iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| match f - { - AssocItemId::FunctionId(f) => Some((ty.clone(), f)), - _ => None, - }) + iterate_method_candidates( + ty, + db, + env, + krate, + &traits_in_scope, + Some(name), + LookupMode::MethodCall, + |ty, f| match f { + AssocItemId::FunctionId(f) => Some((ty.clone(), f)), + _ => None, + }, + ) } /// Whether we're looking up a dotted method call (like `v.len()`) or a path @@ -172,14 +182,13 @@ pub enum LookupMode { pub fn iterate_method_candidates( ty: &Canonical, db: &impl HirDatabase, - resolver: &Resolver, + env: Arc, + krate: CrateId, + traits_in_scope: &FxHashSet, name: Option<&Name>, mode: LookupMode, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - let traits_in_scope = resolver.traits_in_scope(db); - let krate = resolver.krate()?; - let env = TraitEnvironment::lower(db, resolver); match mode { LookupMode::MethodCall => { // For method calls, rust first does any number of autoderef, and then one @@ -190,9 +199,7 @@ pub fn iterate_method_candidates( // Also note that when we've got a receiver like &S, even if the method we // find in the end takes &self, we still do the autoderef step (just as // rustc does an autoderef and then autoref again). - let environment = TraitEnvironment::lower(db, resolver); - let ty = InEnvironment { value: ty.clone(), environment }; - let krate = resolver.krate()?; + let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; // We have to be careful about the order we're looking at candidates // in here. Consider the case where we're resolving `x.clone()` @@ -214,7 +221,7 @@ pub fn iterate_method_candidates( db, env.clone(), krate, - &traits_in_scope, + traits_in_scope, name, &mut callback, ) { @@ -230,7 +237,7 @@ pub fn iterate_method_candidates( db, env, krate, - &traits_in_scope, + traits_in_scope, name, &mut callback, ) -- cgit v1.2.3 From a38540771fa93994c369d53a2abc01769c64c0b8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jan 2020 14:42:52 +0100 Subject: Move Type API to type --- crates/ra_hir/src/code_model.rs | 74 +++++++++++++++++++++++++-- crates/ra_hir/src/source_analyzer.rs | 70 +++---------------------- crates/ra_ide/src/completion/complete_dot.rs | 17 +++--- crates/ra_ide/src/completion/complete_path.rs | 26 +++++----- 4 files changed, 102 insertions(+), 85 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 346118350..3b479356f 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -21,8 +21,8 @@ use hir_expand::{ MacroDefId, }; use hir_ty::{ - autoderef, display::HirFormatter, expr::ExprValidator, method_resolution::implements_trait, - ApplicationTy, Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, + autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy, + Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, }; use ra_db::{CrateId, Edition, FileId}; use ra_prof::profile; @@ -120,7 +120,8 @@ impl_froms!( BuiltinType ); -pub use hir_def::{attr::Attrs, visibility::Visibility}; +pub use hir_def::{attr::Attrs, visibility::Visibility, AssocItemId}; +use rustc_hash::FxHashSet; impl Module { pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { @@ -891,7 +892,13 @@ impl Type { }; let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 }; - implements_trait(&canonical_ty, db, self.ty.environment.clone(), krate, std_future_trait) + method_resolution::implements_trait( + &canonical_ty, + db, + self.ty.environment.clone(), + krate, + std_future_trait, + ) } // FIXME: this method is broken, as it doesn't take closures into account. @@ -1002,6 +1009,65 @@ impl Type { None } + pub fn iterate_method_candidates( + &self, + db: &impl HirDatabase, + krate: Crate, + traits_in_scope: &FxHashSet, + name: Option<&Name>, + mut callback: impl FnMut(&Ty, Function) -> Option, + ) -> Option { + // There should be no inference vars in types passed here + // FIXME check that? + // FIXME replace Unknown by bound vars here + let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; + + let env = self.ty.environment.clone(); + let krate = krate.id; + + method_resolution::iterate_method_candidates( + &canonical, + db, + env, + krate, + traits_in_scope, + name, + method_resolution::LookupMode::MethodCall, + |ty, it| match it { + AssocItemId::FunctionId(f) => callback(ty, f.into()), + _ => None, + }, + ) + } + + pub fn iterate_path_candidates( + &self, + db: &impl HirDatabase, + krate: Crate, + traits_in_scope: &FxHashSet, + name: Option<&Name>, + mut callback: impl FnMut(&Ty, AssocItem) -> Option, + ) -> Option { + // There should be no inference vars in types passed here + // FIXME check that? + // FIXME replace Unknown by bound vars here + let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; + + let env = self.ty.environment.clone(); + let krate = krate.id; + + method_resolution::iterate_method_candidates( + &canonical, + db, + env, + krate, + traits_in_scope, + name, + method_resolution::LookupMode::Path, + |ty, it| callback(ty, it.into()), + ) + } + pub fn as_adt(&self) -> Option { let (adt, _subst) = self.ty.value.as_adt()?; Some(adt.into()) diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 5707a5696..76e0bff34 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -16,12 +16,12 @@ use hir_def::{ expr::{ExprId, PatId}, nameres::ModuleSource, resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, - AssocItemId, DefWithBodyId, + DefWithBodyId, TraitId, }; use hir_expand::{ hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, }; -use hir_ty::{method_resolution, Canonical, InEnvironment, InferenceResult, TraitEnvironment, Ty}; +use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; use ra_prof::profile; use ra_syntax::{ ast::{self, AstNode}, @@ -29,11 +29,11 @@ use ra_syntax::{ SyntaxKind::*, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, }; +use rustc_hash::FxHashSet; use crate::{ - db::HirDatabase, Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, - ImplBlock, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, - TypeParam, + db::HirDatabase, Adt, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, ImplBlock, + Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, }; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of @@ -347,63 +347,9 @@ impl SourceAnalyzer { .collect() } - pub fn iterate_method_candidates( - &self, - db: &impl HirDatabase, - ty: &Type, - name: Option<&Name>, - mut callback: impl FnMut(&Ty, Function) -> Option, - ) -> Option { - // There should be no inference vars in types passed here - // FIXME check that? - // FIXME replace Unknown by bound vars here - let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 }; - - let env = TraitEnvironment::lower(db, &self.resolver); - let krate = self.resolver.krate()?; - let traits_in_scope = self.resolver.traits_in_scope(db); - - method_resolution::iterate_method_candidates( - &canonical, - db, - env, - krate, - &traits_in_scope, - name, - method_resolution::LookupMode::MethodCall, - |ty, it| match it { - AssocItemId::FunctionId(f) => callback(ty, f.into()), - _ => None, - }, - ) - } - - pub fn iterate_path_candidates( - &self, - db: &impl HirDatabase, - ty: &Type, - name: Option<&Name>, - mut callback: impl FnMut(&Ty, AssocItem) -> Option, - ) -> Option { - // There should be no inference vars in types passed here - // FIXME check that? - // FIXME replace Unknown by bound vars here - let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 }; - - let env = TraitEnvironment::lower(db, &self.resolver); - let krate = self.resolver.krate()?; - let traits_in_scope = self.resolver.traits_in_scope(db); - - method_resolution::iterate_method_candidates( - &canonical, - db, - env, - krate, - &traits_in_scope, - name, - method_resolution::LookupMode::Path, - |ty, it| callback(ty, it.into()), - ) + /// Note: `FxHashSet` should be treated as an opaque type, passed into `Type + pub fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet { + self.resolver.traits_in_scope(db) } pub fn expand( diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 9ab43644e..2ca78c927 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs @@ -53,13 +53,16 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty } fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { - let mut seen_methods = FxHashSet::default(); - ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { - if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { - acc.add_function(ctx, func); - } - None::<()> - }); + if let Some(krate) = ctx.module.map(|it| it.krate()) { + let mut seen_methods = FxHashSet::default(); + let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db); + receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { + if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { + acc.add_function(ctx, func); + } + None::<()> + }); + } } #[cfg(test)] diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs index 0dce9dc2d..af24e9f48 100644 --- a/crates/ra_ide/src/completion/complete_path.rs +++ b/crates/ra_ide/src/completion/complete_path.rs @@ -49,22 +49,24 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), _ => unreachable!(), }; - ctx.analyzer.iterate_path_candidates(ctx.db, &ty, None, |_ty, item| { - match item { - hir::AssocItem::Function(func) => { - if !func.has_self_param(ctx.db) { - acc.add_function(ctx, func); - } - } - hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - } - None::<()> - }); // Iterate assoc types separately // FIXME: complete T::AssocType let krate = ctx.module.map(|m| m.krate()); if let Some(krate) = krate { + let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db); + ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { + match item { + hir::AssocItem::Function(func) => { + if !func.has_self_param(ctx.db) { + acc.add_function(ctx, func); + } + } + hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), + hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), + } + None::<()> + }); + ty.iterate_impl_items(ctx.db, krate, |item| { match item { hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} -- cgit v1.2.3