AssocItem::TypeAlias(t) => t.module(db),
}
}
+
+ pub fn container(self, db: &impl DefDatabase) -> Container {
+ match self {
+ AssocItem::Function(f) => f.container(db),
+ AssocItem::Const(c) => c.container(db),
+ AssocItem::TypeAlias(t) => t.container(db),
+ }
+ .expect("AssocItem without container")
+ }
}
let parent = match def {
GenericDef::Function(it) => it.container(db).map(GenericDef::from),
GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
+ GenericDef::Const(it) => it.container(db).map(GenericDef::from),
GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
GenericDef::Adt(_) | GenericDef::Trait(_) => None,
- GenericDef::ImplBlock(_) | GenericDef::Const(_) => None,
+ GenericDef::ImplBlock(_) => None,
};
let mut generics = GenericParams {
def,
ids::LocationCtx,
resolve::{ScopeDef, TypeNs, ValueNs},
ty::method_resolution::implements_trait,
- Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, Module,
- Name, Path, Resolver, Static, Struct, Ty,
+ AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId,
+ MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
};
fn try_get_resolver_for_node(
db: &impl HirDatabase,
ty: Ty,
name: Option<&Name>,
- callback: impl FnMut(&Ty, Function) -> Option<T>,
+ callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
// There should be no inference vars in types passed here
// FIXME check that?
db,
&self.resolver,
name,
+ crate::ty::method_resolution::LookupMode::MethodCall,
callback,
)
}
use crate::{
db::HirDatabase,
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
- ty::{lower, traits::TraitEnvironment, Canonical},
- ty::{Substs, Ty, TypableDef, TypeWalk},
- AssocItem, HasGenericParams, Name, Namespace, Path, Trait,
+ ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk},
+ AssocItem, Container, HasGenericParams, Name, Namespace, Path,
};
-use std::sync::Arc;
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
pub(super) fn infer_path(
return None;
}
- self.find_inherent_assoc_candidate(ty.clone(), name, id)
- .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id))
- }
-
- fn find_inherent_assoc_candidate(
- &mut self,
- ty: Ty,
- name: &Name,
- id: ExprOrPatId,
- ) -> Option<(ValueNs, Option<Substs>)> {
- let krate = self.resolver.krate()?;
-
- // Find impl
- let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
- AssocItem::Function(func) => {
- if *name == func.name(self.db) {
- Some(AssocItem::Function(func))
- } else {
- None
- }
- }
-
- AssocItem::Const(konst) => {
- if konst.name(self.db).map_or(false, |n| n == *name) {
- Some(AssocItem::Const(konst))
- } else {
- None
- }
- }
- AssocItem::TypeAlias(_) => None,
- })?;
- let def = match item {
- AssocItem::Function(f) => ValueNs::Function(f),
- AssocItem::Const(c) => ValueNs::Const(c),
- AssocItem::TypeAlias(_) => unreachable!(),
- };
- let substs = self.find_self_types(&def, ty);
-
- self.write_assoc_resolution(id, item);
- Some((def, substs))
- }
-
- fn find_trait_assoc_candidate(
- &mut self,
- ty: Ty,
- name: &Name,
- id: ExprOrPatId,
- ) -> Option<(ValueNs, Option<Substs>)> {
- let krate = self.resolver.krate()?;
-
let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
- let env = lower::trait_env(self.db, &self.resolver);
- // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
- let traits_from_env = env
- .trait_predicates_for_self_ty(&ty)
- .map(|tr| tr.trait_)
- .flat_map(|t| t.all_super_traits(self.db));
- let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db));
-
- 'traits: for t in traits {
- let data = t.trait_data(self.db);
- let mut known_implemented = false;
- for item in data.items() {
- if let AssocItem::Function(f) = *item {
- if f.name(self.db) == *name {
- if !known_implemented {
- let goal = generic_implements_goal(
- self.db,
- env.clone(),
- t,
- canonical_ty.value.clone(),
- );
- if self.db.trait_solve(krate, goal).is_none() {
- continue 'traits;
- }
- }
- known_implemented = true;
-
+ method_resolution::iterate_method_candidates(
+ &canonical_ty.value,
+ self.db,
+ &self.resolver.clone(),
+ Some(name),
+ method_resolution::LookupMode::Path,
+ move |_ty, item| {
+ let def = match item {
+ AssocItem::Function(f) => ValueNs::Function(f),
+ AssocItem::Const(c) => ValueNs::Const(c),
+ AssocItem::TypeAlias(_) => unreachable!(),
+ };
+ match item.container(self.db) {
+ Container::ImplBlock(_) => {
+ let substs = self.find_self_types(&def, ty.clone());
+
+ self.write_assoc_resolution(id, item);
+ Some((def, substs))
+ }
+ Container::Trait(t) => {
// we're picking this method
let trait_substs = Substs::build_for_def(self.db, t)
.push(ty.clone())
.fill(std::iter::repeat_with(|| self.new_type_var()))
.build();
- let substs = Substs::build_for_def(self.db, f)
+ let substs = Substs::build_for_def(self.db, item)
.use_parent_substs(&trait_substs)
.fill_with_params()
.build();
substs: trait_substs,
}));
- self.write_assoc_resolution(id, *item);
- return Some((ValueNs::Function(f), Some(substs)));
+ self.write_assoc_resolution(id, item);
+ Some((def, Some(substs)))
}
}
- }
- }
-
- None
+ },
+ )
}
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
}
}
}
-
-// TODO remove duplication
-/// This creates Substs for a trait with the given Self type and type variables
-/// for all other parameters, to query Chalk with it.
-fn generic_implements_goal(
- db: &impl HirDatabase,
- env: Arc<TraitEnvironment>,
- trait_: Trait,
- self_ty: Canonical<Ty>,
-) -> Canonical<super::InEnvironment<super::Obligation>> {
- let num_vars = self_ty.num_vars;
- let substs = super::Substs::build_for_def(db, trait_)
- .push(self_ty.value)
- .fill_with_bound_vars(num_vars as u32)
- .build();
- let num_vars = substs.len() - 1 + self_ty.num_vars;
- let trait_ref = TraitRef { trait_, substs };
- let obligation = super::Obligation::Trait(trait_ref);
- Canonical { num_vars, value: super::InEnvironment::new(env, obligation) }
-}
name: &Name,
resolver: &Resolver,
) -> Option<(Ty, Function)> {
- iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
+ iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| {
+ if let AssocItem::Function(f) = f {
+ Some((ty.clone(), f))
+ } else {
+ None
+ }
+ })
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum LookupMode {
+ MethodCall,
+ Path,
}
// This would be nicer if it just returned an iterator, but that runs into
db: &impl HirDatabase,
resolver: &Resolver,
name: Option<&Name>,
- mut callback: impl FnMut(&Ty, Function) -> Option<T>,
+ mode: LookupMode,
+ mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
// For method calls, rust first does any number of autoderef, and then one
// autoref (i.e. when the method takes &self or &mut self). We just ignore
// rustc does an autoderef and then autoref again).
let krate = resolver.krate()?;
+ // TODO no autoderef in LookupMode::Path
for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
- if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
+ if let Some(result) =
+ iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback)
{
return Some(result);
}
if let Some(result) =
- iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
+ iterate_trait_method_candidates(&derefed_ty, db, resolver, name, mode, &mut callback)
{
return Some(result);
}
db: &impl HirDatabase,
resolver: &Resolver,
name: Option<&Name>,
- mut callback: impl FnMut(&Ty, Function) -> Option<T>,
+ mode: LookupMode,
+ mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
let krate = resolver.krate()?;
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
// trait, but if we find out it doesn't, we'll skip the rest of the
// iteration
let mut known_implemented = inherently_implemented;
- for item in data.items() {
- if let AssocItem::Function(m) = *item {
- let data = m.data(db);
- if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
- if !known_implemented {
- let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
- if db.trait_solve(krate, goal).is_none() {
- continue 'traits;
- }
+ for &item in data.items() {
+ // TODO unify with the impl case
+ match item {
+ AssocItem::Function(m) => {
+ let data = m.data(db);
+ if !name.map_or(true, |name| data.name() == name)
+ || (!data.has_self_param() && mode != LookupMode::Path)
+ {
+ continue;
}
- known_implemented = true;
- if let Some(result) = callback(&ty.value, m) {
- return Some(result);
+ }
+ AssocItem::Const(c) => {
+ if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
+ || (mode != LookupMode::Path)
+ {
+ continue;
}
}
+ _ => {}
+ };
+ if !known_implemented {
+ let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
+ if db.trait_solve(krate, goal).is_none() {
+ continue 'traits;
+ }
+ }
+ known_implemented = true;
+ if let Some(result) = callback(&ty.value, item) {
+ return Some(result);
}
}
}
ty: &Canonical<Ty>,
db: &impl HirDatabase,
name: Option<&Name>,
+ mode: LookupMode,
krate: Crate,
- mut callback: impl FnMut(&Ty, Function) -> Option<T>,
+ mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
for krate in def_crates(db, krate, &ty.value)? {
let impls = db.impls_in_crate(krate);
for impl_block in impls.lookup_impl_blocks(&ty.value) {
for item in impl_block.items(db) {
- if let AssocItem::Function(f) = item {
- let data = f.data(db);
- if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
- if let Some(result) = callback(&ty.value, f) {
- return Some(result);
+ match item {
+ AssocItem::Function(f) => {
+ let data = f.data(db);
+ if !name.map_or(true, |name| data.name() == name)
+ || (!data.has_self_param() && mode != LookupMode::Path)
+ {
+ continue;
}
}
+ AssocItem::Const(c) => {
+ if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
+ || (mode != LookupMode::Path)
+ {
+ continue;
+ }
+ }
+ _ => {}
+ }
+ if let Some(result) = callback(&ty.value, item) {
+ return Some(result);
}
}
}
[243; 254) 'Struct::FOO': u32
[264; 265) 'y': u32
[268; 277) 'Enum::BAR': u32
- [287; 288) 'z': {unknown}
- [291; 304) 'TraitTest::ID': {unknown}
+ [287; 288) 'z': u32
+ [291; 304) 'TraitTest::ID': u32
"###
);
}
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
let mut seen_methods = FxHashSet::default();
- ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
- let data = func.data(ctx.db);
- if data.has_self_param() && seen_methods.insert(data.name().clone()) {
- acc.add_function(ctx, func);
+ ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, item| {
+ if let hir::AssocItem::Function(func) = item {
+ let data = func.data(ctx.db);
+ if data.has_self_param() && seen_methods.insert(data.name().clone()) {
+ acc.add_function(ctx, func);
+ }
}
None::<()>
});