Repository: rust-analyzer/rust-analyzer
Pull request #2151 (2019-10-31 23:41:11)

Resolve (and complete) trait calls like `Vec::default()`
Similar to rustc, we do this using the same code as the method call resolution, just without doing autoderef (and considering more potential candidates).

(Btw, we currently don't complete methods with `self` in path notation, even though they'd be legal to use, so maybe we should -- on the other hand, that will usually not be the most interesting completions...)

flodiebold: > I feel this best is solved by looking at the expected at the call-site, and making an approtiate suggestion when the type fits.

Not sure I understand what you mean here. My point was that instead of e.g. `v.len()`, one could write `Vec::len(&v)`, but we currently don't complete `Vec::len` because we explicitly exclude methods with self parameter for path completion.

Patch:
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index ae6ef76067..c97ea18a24 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1053,4 +1053,13 @@ impl AssocItem {
             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")
+    }
 }
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 52e1fbf294..9c261eda9f 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -77,9 +77,10 @@ impl GenericParams {
         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,
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 0008cb232d..a4ca59bba1 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -27,9 +27,9 @@ use crate::{
     },
     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,
+    ty::method_resolution::{self, implements_trait},
+    AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId,
+    MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
 };
 
 fn try_get_resolver_for_node(
@@ -327,16 +327,42 @@ impl SourceAnalyzer {
         db: &impl HirDatabase,
         ty: Ty,
         name: Option<&Name>,
-        callback: impl FnMut(&Ty, Function) -> Option<T>,
+        mut callback: impl FnMut(&Ty, Function) -> Option<T>,
     ) -> Option<T> {
         // There should be no inference vars in types passed here
         // FIXME check that?
+        // FIXME replace Unknown by bound vars here
         let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
-        crate::ty::method_resolution::iterate_method_candidates(
+        method_resolution::iterate_method_candidates(
             &canonical,
             db,
             &self.resolver,
             name,
+            method_resolution::LookupMode::MethodCall,
+            |ty, it| match it {
+                AssocItem::Function(f) => callback(ty, f),
+                _ => None,
+            },
+        )
+    }
+
+    pub fn iterate_path_candidates<T>(
+        &self,
+        db: &impl HirDatabase,
+        ty: Ty,
+        name: Option<&Name>,
+        callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
+    ) -> Option<T> {
+        // There should be no inference vars in types passed here
+        // FIXME check that?
+        // FIXME replace Unknown by bound vars here
+        let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
+        method_resolution::iterate_method_candidates(
+            &canonical,
+            db,
+            &self.resolver,
+            name,
+            method_resolution::LookupMode::Path,
             callback,
         )
     }
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d2bfcdc7db..d1a9d74111 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -385,13 +385,22 @@ impl SubstsBuilder {
         self.param_count - self.vec.len()
     }
 
-    pub fn fill_with_bound_vars(mut self, starting_from: u32) -> Self {
-        self.vec.extend((starting_from..starting_from + self.remaining() as u32).map(Ty::Bound));
-        self
+    pub fn fill_with_bound_vars(self, starting_from: u32) -> Self {
+        self.fill((starting_from..).map(Ty::Bound))
+    }
+
+    pub fn fill_with_params(self) -> Self {
+        let start = self.vec.len() as u32;
+        self.fill((start..).map(|idx| Ty::Param { idx, name: Name::missing() }))
+    }
+
+    pub fn fill_with_unknown(self) -> Self {
+        self.fill(iter::repeat(Ty::Unknown))
     }
 
-    pub fn fill_with_unknown(mut self) -> Self {
-        self.vec.extend(iter::repeat(Ty::Unknown).take(self.remaining()));
+    pub fn fill(mut self, filler: impl Iterator<Item = Ty>) -> Self {
+        self.vec.extend(filler.take(self.remaining()));
+        assert_eq!(self.remaining(), 0);
         self
     }
 
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index 77aa35ce13..59b7f7eb64 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -6,8 +6,8 @@ use super::{ExprOrPatId, InferenceContext, TraitRef};
 use crate::{
     db::HirDatabase,
     resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
-    ty::{Substs, Ty, TypableDef, TypeWalk},
-    AssocItem, HasGenericParams, Namespace, Path,
+    ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk},
+    AssocItem, Container, HasGenericParams, Name, Namespace, Path,
 };
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@@ -39,7 +39,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
             self.resolve_ty_assoc_item(
                 ty,
-                path.segments.last().expect("path had at least one segment"),
+                &path.segments.last().expect("path had at least one segment").name,
                 id,
             )?
         } else {
@@ -122,10 +122,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                     return None;
                 }
 
+                let ty = self.insert_type_vars(ty);
+                let ty = self.normalize_associated_types_in(ty);
+
                 let segment =
                     remaining_segments.last().expect("there should be at least one segment here");
 
-                self.resolve_ty_assoc_item(ty, segment, id)
+                self.resolve_ty_assoc_item(ty, &segment.name, id)
             }
         }
     }
@@ -162,7 +165,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         };
         let substs = Substs::build_for_def(self.db, item)
             .use_parent_substs(&trait_ref.substs)
-            .fill_with_unknown()
+            .fill_with_params()
             .build();
 
         self.write_assoc_resolution(id, item);
@@ -172,44 +175,51 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     fn resolve_ty_assoc_item(
         &mut self,
         ty: Ty,
-        segment: &PathSegment,
+        name: &Name,
         id: ExprOrPatId,
     ) -> Option<(ValueNs, Option<Substs>)> {
         if let Ty::Unknown = ty {
             return None;
         }
 
-        let krate = self.resolver.krate()?;
-
-        // Find impl
-        // FIXME: consider trait candidates
-        let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
-            AssocItem::Function(func) => {
-                if segment.name == func.name(self.db) {
-                    Some(AssocItem::Function(func))
-                } else {
-                    None
-                }
-            }
-
-            AssocItem::Const(konst) => {
-                if konst.name(self.db).map_or(false, |n| n == segment.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);
+        let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
+
+        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!(),
+                };
+                let substs = match item.container(self.db) {
+                    Container::ImplBlock(_) => self.find_self_types(&def, ty.clone()),
+                    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, item)
+                            .use_parent_substs(&trait_substs)
+                            .fill_with_params()
+                            .build();
+                        self.obligations.push(super::Obligation::Trait(TraitRef {
+                            trait_: t,
+                            substs: trait_substs,
+                        }));
+                        Some(substs)
+                    }
+                };
 
-        self.write_assoc_resolution(id, item);
-        Some((def, substs))
+                self.write_assoc_resolution(id, item);
+                Some((def, substs))
+            },
+        )
     }
 
     fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index eb69344f6a..8c3d32d09d 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -166,37 +166,78 @@ 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| match f
+    {
+        AssocItem::Function(f) => Some((ty.clone(), f)),
+        _ => None,
+    })
+}
+
+/// Whether we're looking up a dotted method call (like `v.len()`) or a path
+/// (like `Vec::new`).
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum LookupMode {
+    /// Looking up a method call like `v.len()`: We only consider candidates
+    /// that have a `self` parameter, and do autoderef.
+    MethodCall,
+    /// Looking up a path like `Vec::new` or `Vec::default`: We consider all
+    /// candidates including associated constants, but don't do autoderef.
+    Path,
 }
 
 // This would be nicer if it just returned an iterator, but that runs into
 // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
+// FIXME add a context type here?
 pub(crate) fn iterate_method_candidates<T>(
     ty: &Canonical<Ty>,
     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
-    // the autoref currently -- when we find a method matching the given name,
-    // we assume it fits.
+    let krate = resolver.krate()?;
+    match mode {
+        LookupMode::MethodCall => {
+            // 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
+            // the autoref currently -- when we find a method matching the given name,
+            // we assume it fits.
 
-    // 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).
+            // 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 krate = resolver.krate()?;
-    for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
-        if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
-        {
-            return Some(result);
+            for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
+                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,
+                    mode,
+                    &mut callback,
+                ) {
+                    return Some(result);
+                }
+            }
         }
-        if let Some(result) =
-            iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
-        {
-            return Some(result);
+        LookupMode::Path => {
+            // No autoderef for path lookups
+            if let Some(result) =
+                iterate_inherent_methods(&ty, db, name, mode, krate, &mut callback)
+            {
+                return Some(result);
+            }
+            if let Some(result) =
+                iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback)
+            {
+                return Some(result);
+            }
         }
     }
     None
@@ -207,7 +248,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,22 +273,20 @@ 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;
-                        }
-                    }
-                    known_implemented = true;
-                    if let Some(result) = callback(&ty.value, m) {
-                        return Some(result);
-                    }
+        for &item in data.items() {
+            if !is_valid_candidate(db, name, mode, item) {
+                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);
+            }
         }
     }
     None
@@ -256,21 +296,20 @@ 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);
-                        }
-                    }
+                if !is_valid_candidate(db, name, mode, item) {
+                    continue;
+                }
+                if let Some(result) = callback(&ty.value, item) {
+                    return Some(result);
                 }
             }
         }
@@ -278,6 +317,26 @@ fn iterate_inherent_methods<T>(
     None
 }
 
+fn is_valid_candidate(
+    db: &impl HirDatabase,
+    name: Option<&Name>,
+    mode: LookupMode,
+    item: AssocItem,
+) -> bool {
+    match item {
+        AssocItem::Function(m) => {
+            let data = m.data(db);
+            name.map_or(true, |name| data.name() == name)
+                && (data.has_self_param() || mode == LookupMode::Path)
+        }
+        AssocItem::Const(c) => {
+            name.map_or(true, |name| Some(name) == c.name(db).as_ref())
+                && (mode == LookupMode::Path)
+        }
+        _ => false,
+    }
+}
+
 pub(crate) fn implements_trait(
     ty: &Canonical<Ty>,
     db: &impl HirDatabase,
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index a58fdc036f..9ac9768afb 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -50,23 +50,46 @@ 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.clone(), None, |_ty, item| {
+                match item {
+                    hir::AssocItem::Function(func) => {
+                        let data = func.data(ctx.db);
+                        if !data.has_self_param() {
+                            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 {
                 ty.iterate_impl_items(ctx.db, krate, |item| {
                     match item {
-                        hir::AssocItem::Function(func) => {
-                            let data = func.data(ctx.db);
-                            if !data.has_self_param() {
-                                acc.add_function(ctx, func);
-                            }
-                        }
-                        hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+                        hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}
                         hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
                     }
                     None::<()>
                 });
             }
         }
+        hir::ModuleDef::Trait(t) => {
+            for item in t.items(ctx.db) {
+                match item {
+                    hir::AssocItem::Function(func) => {
+                        let data = func.data(ctx.db);
+                        if !data.has_self_param() {
+                            acc.add_function(ctx, func);
+                        }
+                    }
+                    hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+                    hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+                }
+            }
+        }
         _ => {}
     };
 }
@@ -558,6 +581,111 @@ mod tests {
         );
     }
 
+    #[test]
+    fn completes_trait_associated_method_1() {
+        assert_debug_snapshot!(
+            do_reference_completion(
+                "
+                //- /lib.rs
+                trait Trait {
+                  /// A trait method
+                  fn m();
+                }
+
+                fn foo() { let _ = Trait::<|> }
+                "
+            ),
+            @r###"
+        [
+            CompletionItem {
+                label: "m()",
+                source_range: [73; 73),
+                delete: [73; 73),
+                insert: "m()$0",
+                kind: Function,
+                lookup: "m",
+                detail: "fn m()",
+                documentation: Documentation(
+                    "A trait method",
+                ),
+            },
+        ]
+        "###
+        );
+    }
+
+    #[test]
+    fn completes_trait_associated_method_2() {
+        assert_debug_snapshot!(
+            do_reference_completion(
+                "
+                //- /lib.rs
+                trait Trait {
+                  /// A trait method
+                  fn m();
+                }
+
+                struct S;
+                impl Trait for S {}
+
+                fn foo() { let _ = S::<|> }
+                "
+            ),
+            @r###"
+        [
+            CompletionItem {
+                label: "m()",
+                source_range: [99; 99),
+                delete: [99; 99),
+                insert: "m()$0",
+                kind: Function,
+                lookup: "m",
+                detail: "fn m()",
+                documentation: Documentation(
+                    "A trait method",
+                ),
+            },
+        ]
+        "###
+        );
+    }
+
+    #[test]
+    fn completes_trait_associated_method_3() {
+        assert_debug_snapshot!(
+            do_reference_completion(
+                "
+                //- /lib.rs
+                trait Trait {
+                  /// A trait method
+                  fn m();
+                }
+
+                struct S;
+                impl Trait for S {}
+
+                fn foo() { let _ = <S as Trait>::<|> }
+                "
+            ),
+            @r###"
+        [
+            CompletionItem {
+                label: "m()",
+                source_range: [110; 110),
+                delete: [110; 110),
+                insert: "m()$0",
+                kind: Function,
+                lookup: "m",
+                detail: "fn m()",
+                documentation: Documentation(
+                    "A trait method",
+                ),
+            },
+        ]
+        "###
+        );
+    }
+
     #[test]
     fn completes_type_alias() {
         assert_debug_snapshot!(
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 323faab335..c1ce54bea3 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -390,6 +390,61 @@ mod tests {
             "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
         );
     }
+
+    #[test]
+    fn goto_definition_works_for_ufcs_inherent_methods() {
+        check_goto(
+            "
+            //- /lib.rs
+            struct Foo;
+            impl Foo {
+                fn frobnicate() {  }
+            }
+
+            fn bar(foo: &Foo) {
+                Foo::frobnicate<|>();
+            }
+            ",
+            "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)",
+        );
+    }
+
+    #[test]
+    fn goto_definition_works_for_ufcs_trait_methods_through_traits() {
+        check_goto(
+            "
+            //- /lib.rs
+            trait Foo {
+                fn frobnicate();
+            }
+
+            fn bar() {
+                Foo::frobnicate<|>();
+            }
+            ",
+            "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
+        );
+    }
+
+    #[test]
+    fn goto_definition_works_for_ufcs_trait_methods_through_self() {
+        check_goto(
+            "
+            //- /lib.rs
+            struct Foo;
+            trait Trait {
+                fn frobnicate();
+            }
+            impl Trait for Foo {}
+
+            fn bar() {
+                Foo::frobnicate<|>();
+            }
+            ",
+            "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
+        );
+    }
+
     #[test]
     fn goto_definition_on_self() {
         check_goto(


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c12326643c..bfef48b161 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -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
     "###
     );
 }
@@ -2782,9 +2782,9 @@ fn test() {
     [97; 99) 's1': S
     [105; 121) 'Defaul...efault': fn default<S>() -> Self
     [105; 123) 'Defaul...ault()': S
-    [133; 135) 's2': {unknown}
-    [138; 148) 'S::default': {unknown}
-    [138; 150) 'S::default()': {unknown}
+    [133; 135) 's2': S
+    [138; 148) 'S::default': fn default<S>() -> Self
+    [138; 150) 'S::default()': S
     [160; 162) 's3': S
     [165; 188) '<S as ...efault': fn default<S>() -> Self
     [165; 190) '<S as ...ault()': S
@@ -2792,6 +2792,153 @@ fn test() {
     );
 }
 
+#[test]
+fn infer_trait_assoc_method_generics_1() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn make() -> T;
+}
+struct S;
+impl Trait<u32> for S {}
+struct G<T>;
+impl<T> Trait<T> for G<T> {}
+fn test() {
+    let a = S::make();
+    let b = G::<u64>::make();
+    let c: f64 = G::make();
+}
+"#),
+        @r###"
+    [127; 211) '{     ...e(); }': ()
+    [137; 138) 'a': u32
+    [141; 148) 'S::make': fn make<S, u32>() -> T
+    [141; 150) 'S::make()': u32
+    [160; 161) 'b': u64
+    [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
+    [164; 180) 'G::<u6...make()': u64
+    [190; 191) 'c': f64
+    [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
+    [199; 208) 'G::make()': f64
+    "###
+    );
+}
+
+#[test]
+fn infer_trait_assoc_method_generics_2() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn make<U>() -> (T, U);
+}
+struct S;
+impl Trait<u32> for S {}
+struct G<T>;
+impl<T> Trait<T> for G<T> {}
+fn test() {
+    let a = S::make::<i64>();
+    let b: (_, i64) = S::make();
+    let c = G::<u32>::make::<i64>();
+    let d: (u32, _) = G::make::<i64>();
+    let e: (u32, i64) = G::make();
+}
+"#),
+        @r###"
+    [135; 313) '{     ...e(); }': ()
+    [145; 146) 'a': (u32, i64)
+    [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
+    [149; 165) 'S::mak...i64>()': (u32, i64)
+    [175; 176) 'b': (u32, i64)
+    [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
+    [189; 198) 'S::make()': (u32, i64)
+    [208; 209) 'c': (u32, i64)
+    [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
+    [212; 235) 'G::<u3...i64>()': (u32, i64)
+    [245; 246) 'd': (u32, i64)
+    [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
+    [259; 275) 'G::mak...i64>()': (u32, i64)
+    [285; 286) 'e': (u32, i64)
+    [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
+    [301; 310) 'G::make()': (u32, i64)
+    "###
+    );
+}
+
+#[test]
+fn infer_trait_assoc_method_generics_3() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn make() -> (Self, T);
+}
+struct S<T>;
+impl Trait<i64> for S<i32> {}
+fn test() {
+    let a = S::make();
+}
+"#),
+        @r###"
+    [101; 127) '{     ...e(); }': ()
+    [111; 112) 'a': (S<i32>, i64)
+    [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T)
+    [115; 124) 'S::make()': (S<i32>, i64)
+    "###
+    );
+}
+
+#[test]
+fn infer_trait_assoc_method_generics_4() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn make() -> (Self, T);
+}
+struct S<T>;
+impl Trait<i64> for S<u64> {}
+impl Trait<i32> for S<u32> {}
+fn test() {
+    let a: (S<u64>, _) = S::make();
+    let b: (_, i32) = S::make();
+}
+"#),
+        @r###"
+    [131; 203) '{     ...e(); }': ()
+    [141; 142) 'a': (S<u64>, i64)
+    [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T)
+    [158; 167) 'S::make()': (S<u64>, i64)
+    [177; 178) 'b': (S<u32>, i32)
+    [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T)
+    [191; 200) 'S::make()': (S<u32>, i32)
+    "###
+    );
+}
+
+#[test]
+fn infer_trait_assoc_method_generics_5() {
+    assert_snapshot!(
+        infer(r#"
+trait Trait<T> {
+    fn make<U>() -> (Self, T, U);
+}
+struct S<T>;
+impl Trait<i64> for S<u64> {}
+fn test() {
+    let a = <S as Trait<i64>>::make::<u8>();
+    let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
+}
+"#),
+        @r###"
+    [107; 211) '{     ...>(); }': ()
+    [117; 118) 'a': (S<u64>, i64, u8)
+    [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
+    [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
+    [162; 163) 'b': (S<u64>, i64, u8)
+    [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
+    [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
+    "###
+    );
+}
+
 #[test]
 fn infer_from_bound_1() {
     assert_snapshot!(
@@ -3303,6 +3450,22 @@ fn test() { S.foo()<|>; }
     assert_eq!(t, "u128");
 }
 
+#[ignore]
+#[test]
+fn method_resolution_by_value_before_autoref() {
+    let t = type_at(
+        r#"
+//- /main.rs
+trait Clone { fn clone(&self) -> Self; }
+struct S;
+impl Clone for S {}
+impl Clone for &S {}
+fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
+"#,
+    );
+    assert_eq!(t, "(S, S, &S)");
+}
+
 #[test]
 fn method_resolution_trait_before_autoderef() {
     let t = type_at(