]> git.lizzy.rs Git - rust.git/commitdiff
Refactor to unify with method resolution
authorFlorian Diebold <flodiebold@gmail.com>
Thu, 31 Oct 2019 18:28:33 +0000 (19:28 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 1 Nov 2019 18:57:08 +0000 (19:57 +0100)
crates/ra_hir/src/code_model.rs
crates/ra_hir/src/generics.rs
crates/ra_hir/src/source_binder.rs
crates/ra_hir/src/ty/infer/path.rs
crates/ra_hir/src/ty/method_resolution.rs
crates/ra_hir/src/ty/tests.rs
crates/ra_ide_api/src/completion/complete_dot.rs

index ae6ef760674c23859df9a23f9de4e96ae6c3ea75..c97ea18a24ea0f6e45373716c60090f278f048ae 100644 (file)
@@ -1053,4 +1053,13 @@ pub fn module(self, db: &impl DefDatabase) -> Module {
             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")
+    }
 }
index 52e1fbf2946b121047a93e50230dfb9a11a86583..9c261eda9f01ad5d97a532d2de63ffbaefb010c7 100644 (file)
@@ -77,9 +77,10 @@ pub(crate) fn generic_params_query(
         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,
index 0008cb232ddf8bf8d0e69c1fd28d74e960957576..0398806fd18db5b2cde1f54854e20835fb474c82 100644 (file)
@@ -28,8 +28,8 @@
     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(
@@ -327,7 +327,7 @@ pub fn iterate_method_candidates<T>(
         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?
@@ -337,6 +337,7 @@ pub fn iterate_method_candidates<T>(
             db,
             &self.resolver,
             name,
+            crate::ty::method_resolution::LookupMode::MethodCall,
             callback,
         )
     }
index c58564b22fe020dba39837694c27e7c4fc4e99df..1946bf608418dbe1c5f72c7decec327526a5e9ba 100644 (file)
@@ -6,11 +6,9 @@
 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(
@@ -184,91 +182,34 @@ fn resolve_ty_assoc_item(
             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();
@@ -277,14 +218,12 @@ fn find_trait_assoc_candidate(
                             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> {
@@ -317,23 +256,3 @@ 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) }
-}
index eb69344f6a7425ae9f765cbddbe3ba28e1fe8bfb..ee0c7b00f3bc7100981303d32ce33be2c2eb378c 100644 (file)
@@ -166,7 +166,19 @@ pub(crate) fn lookup_method(
     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
@@ -176,7 +188,8 @@ pub(crate) fn iterate_method_candidates<T>(
     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
@@ -188,13 +201,15 @@ pub(crate) fn iterate_method_candidates<T>(
     // 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);
         }
@@ -207,7 +222,8 @@ fn iterate_trait_method_candidates<T>(
     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)
@@ -231,21 +247,35 @@ fn iterate_trait_method_candidates<T>(
         // 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);
             }
         }
     }
@@ -256,21 +286,35 @@ fn iterate_inherent_methods<T>(
     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);
                 }
             }
         }
index e071e4d4e893e76cad550287c5e7f1fc082d2d91..bfef48b1613a5a29c3a1ebaa043a52098e487337 100644 (file)
@@ -1841,8 +1841,8 @@ fn test() {
     [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
     "###
     );
 }
index b4df6ee2ad04ef47f04fa2741689c9834bcea745..7135f481d04d5b51198076aa8452dae4ac17ea65 100644 (file)
@@ -58,10 +58,12 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
 
 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::<()>
     });