about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTavo Annus <tavo.annus@gmail.com>2023-12-16 16:29:23 +0200
committerTavo Annus <tavo.annus@gmail.com>2024-02-11 13:33:29 +0200
commit627255dd5afb661819a4cd831b765c846a0c02aa (patch)
tree905f53e31e7891932d559de7e1473596a13f80b7
parent35eb0dbbc01b20c9b596ea495b2b37b562b87426 (diff)
downloadrust-627255dd5afb661819a4cd831b765c846a0c02aa.tar.gz
rust-627255dd5afb661819a4cd831b765c846a0c02aa.zip
Add static method tactic
-rw-r--r--crates/hir-def/src/attr.rs39
-rw-r--r--crates/hir/src/lib.rs102
-rw-r--r--crates/hir/src/term_search/mod.rs7
-rw-r--r--crates/hir/src/term_search/tactics.rs348
-rw-r--r--crates/hir/src/term_search/type_tree.rs115
-rw-r--r--crates/ide-assists/src/handlers/term_search.rs38
-rw-r--r--crates/ide-db/src/path_transform.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs11
8 files changed, 569 insertions, 93 deletions
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index c91a5497262..247ec096cbe 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -377,27 +377,36 @@ impl AttrsWithOwner {
             AttrDefId::GenericParamId(it) => match it {
                 GenericParamId::ConstParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::TypeParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::LifetimeParamId(it) => {
                     let src = it.parent.child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    match src.value.get(it.local_id) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 24323284e9b..9b8c7b900ae 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1187,6 +1187,10 @@ impl Struct {
     fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
         db.struct_data(self.id).variant_data.clone()
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Struct {
@@ -1229,6 +1233,10 @@ impl Union {
     fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
         db.union_data(self.id).variant_data.clone()
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Union {
@@ -1318,6 +1326,10 @@ impl Enum {
     pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
         Adt::from(self).layout(db)
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 impl HasVisibility for Enum {
@@ -1393,6 +1405,10 @@ impl Variant {
             _ => parent_layout,
         })
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(self.id.into()).is_unstable()
+    }
 }
 
 /// Variants inherit visibility from the parent enum.
@@ -2912,7 +2928,7 @@ impl GenericDef {
             .collect()
     }
 
-    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
+    pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
         let generics = db.generic_params(self.into());
         generics
             .type_or_consts
@@ -2922,6 +2938,40 @@ impl GenericDef {
             })
             .collect()
     }
+
+    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
+        let generics = db.generic_params(self.into());
+        generics
+            .type_or_consts
+            .iter()
+            .filter_map(|(local_id, data)| match data {
+                hir_def::generics::TypeOrConstParamData::TypeParamData(_) => Some(TypeParam {
+                    id: TypeParamId::from_unchecked(TypeOrConstParamId {
+                        parent: self.into(),
+                        local_id,
+                    }),
+                }),
+                hir_def::generics::TypeOrConstParamData::ConstParamData(_) => None,
+            })
+            .collect()
+    }
+
+    pub fn const_params(self, db: &dyn HirDatabase) -> Vec<ConstParam> {
+        let generics = db.generic_params(self.into());
+        generics
+            .type_or_consts
+            .iter()
+            .filter_map(|(local_id, data)| match data {
+                hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
+                hir_def::generics::TypeOrConstParamData::ConstParamData(_) => Some(ConstParam {
+                    id: ConstParamId::from_unchecked(TypeOrConstParamId {
+                        parent: self.into(),
+                        local_id,
+                    }),
+                }),
+            })
+            .collect()
+    }
 }
 
 /// A single local definition.
@@ -3284,12 +3334,16 @@ impl TypeParam {
         let ty = generic_arg_from_param(db, self.id.into())?;
         let resolver = self.id.parent().resolver(db.upcast());
         match ty.data(Interner) {
-            GenericArgData::Ty(it) => {
+            GenericArgData::Ty(it) if *it.kind(Interner) != TyKind::Error => {
                 Some(Type::new_with_resolver_inner(db, &resolver, it.clone()))
             }
             _ => None,
         }
     }
+
+    pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+        db.attrs(GenericParamId::from(self.id).into()).is_unstable()
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -3773,6 +3827,50 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
+    pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool {
+        return go(db, self.env.krate, &self.ty);
+
+        fn go(db: &dyn HirDatabase, krate: CrateId, ty: &Ty) -> bool {
+            match ty.kind(Interner) {
+                // Reference itself
+                TyKind::Ref(_, _, _) => true,
+
+                // For non-phantom_data adts we check variants/fields as well as generic parameters
+                TyKind::Adt(adt_id, substitution)
+                    if !db.struct_datum(krate, *adt_id).flags.phantom_data =>
+                {
+                    let adt_datum = &db.struct_datum(krate, *adt_id);
+                    let adt_datum_bound =
+                        adt_datum.binders.clone().substitute(Interner, substitution);
+                    adt_datum_bound
+                        .variants
+                        .into_iter()
+                        .flat_map(|variant| variant.fields.into_iter())
+                        .any(|ty| go(db, krate, &ty))
+                        || substitution
+                            .iter(Interner)
+                            .filter_map(|x| x.ty(Interner))
+                            .any(|ty| go(db, krate, ty))
+                }
+                // And for `PhantomData<T>`, we check `T`.
+                TyKind::Adt(_, substitution)
+                | TyKind::Tuple(_, substitution)
+                | TyKind::OpaqueType(_, substitution)
+                | TyKind::AssociatedType(_, substitution)
+                | TyKind::FnDef(_, substitution) => substitution
+                    .iter(Interner)
+                    .filter_map(|x| x.ty(Interner))
+                    .any(|ty| go(db, krate, ty)),
+
+                // For `[T]` or `*T` we check `T`
+                TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, krate, ty),
+
+                // Consider everything else as not reference
+                _ => false,
+            }
+        }
+    }
+
     pub fn as_reference(&self) -> Option<(Type, Mutability)> {
         let (ty, _lt, m) = self.ty.as_reference()?;
         let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
diff --git a/crates/hir/src/term_search/mod.rs b/crates/hir/src/term_search/mod.rs
index 6ea5b105def..009d561e7d1 100644
--- a/crates/hir/src/term_search/mod.rs
+++ b/crates/hir/src/term_search/mod.rs
@@ -47,6 +47,8 @@ struct LookupTable {
     round_scopedef_hits: FxHashSet<ScopeDef>,
     /// Amount of rounds since scopedef was first used.
     rounds_since_sopedef_hit: FxHashMap<ScopeDef, u32>,
+    /// Types queried but not present
+    types_wishlist: FxHashSet<Type>,
 }
 
 impl LookupTable {
@@ -149,6 +151,10 @@ impl LookupTable {
     fn exhausted_scopedefs(&self) -> &FxHashSet<ScopeDef> {
         &self.exhausted_scopedefs
     }
+
+    fn take_types_wishlist(&mut self) -> FxHashSet<Type> {
+        std::mem::take(&mut self.types_wishlist)
+    }
 }
 
 /// # Term search
@@ -205,6 +211,7 @@ pub fn term_search<DB: HirDatabase>(
         solutions.extend(tactics::free_function(sema.db, &module, &defs, &mut lookup, goal));
         solutions.extend(tactics::impl_method(sema.db, &module, &defs, &mut lookup, goal));
         solutions.extend(tactics::struct_projection(sema.db, &module, &defs, &mut lookup, goal));
+        solutions.extend(tactics::impl_static_method(sema.db, &module, &defs, &mut lookup, goal));
 
         // Break after 1 round after successful solution
         if solution_found {
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index 34ff420a814..2a9d0d84518 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -8,7 +8,8 @@
 //! * `goal` - Term search target type
 //! And they return iterator that yields type trees that unify with the `goal` type.
 
-use hir_def::generics::TypeOrConstParamData;
+use std::iter;
+
 use hir_ty::db::HirDatabase;
 use hir_ty::mir::BorrowKind;
 use hir_ty::TyBuilder;
@@ -16,8 +17,8 @@ use itertools::Itertools;
 use rustc_hash::FxHashSet;
 
 use crate::{
-    Adt, AssocItem, Enum, GenericParam, HasVisibility, Impl, Module, ModuleDef, ScopeDef, Type,
-    Variant,
+    Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, Module, ModuleDef,
+    ScopeDef, Type, Variant,
 };
 
 use crate::term_search::TypeTree;
@@ -78,7 +79,7 @@ pub(super) fn trivial<'a>(
         lookup.insert(ty.clone(), std::iter::once(tt.clone()));
 
         // Don't suggest local references as they are not valid for return
-        if matches!(tt, TypeTree::Local(_)) && ty.is_reference() {
+        if matches!(tt, TypeTree::Local(_)) && ty.contains_reference(db) {
             return None;
         }
 
@@ -113,37 +114,67 @@ pub(super) fn type_constructor<'a>(
         variant: Variant,
         goal: &Type,
     ) -> Vec<(Type, Vec<TypeTree>)> {
-        let generics = db.generic_params(variant.parent_enum(db).id.into());
+        let generics = GenericDef::from(variant.parent_enum(db));
+
+        // Ignore unstable variants
+        if variant.is_unstable(db) {
+            return Vec::new();
+        }
 
         // Ignore enums with const generics
-        if generics
-            .type_or_consts
-            .values()
-            .any(|it| matches!(it, TypeOrConstParamData::ConstParamData(_)))
-        {
+        if !generics.const_params(db).is_empty() {
             return Vec::new();
         }
 
         // We currently do not check lifetime bounds so ignore all types that have something to do
         // with them
-        if !generics.lifetimes.is_empty() {
+        if !generics.lifetime_params(db).is_empty() {
+            return Vec::new();
+        }
+
+        // Only account for stable type parameters for now
+        let type_params = generics.type_params(db);
+
+        // Only account for stable type parameters for now, unstable params can be default
+        // tho, for example in `Box<T, #[unstable] A: Allocator>`
+        if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
             return Vec::new();
         }
 
+        let non_default_type_params_len =
+            type_params.iter().filter(|it| it.default(db).is_none()).count();
+
         let generic_params = lookup
             .iter_types()
             .collect::<Vec<_>>() // Force take ownership
             .into_iter()
-            .permutations(generics.type_or_consts.len());
+            .permutations(non_default_type_params_len);
 
         generic_params
             .filter_map(|generics| {
+                // Insert default type params
+                let mut g = generics.into_iter();
+                let generics: Vec<_> = type_params
+                    .iter()
+                    .map(|it| match it.default(db) {
+                        Some(ty) => ty,
+                        None => g.next().expect("Missing type param"),
+                    })
+                    .collect();
+
                 let enum_ty = parent_enum.ty_with_generics(db, generics.iter().cloned());
 
+                // Allow types with generics only if they take us straight to goal for
+                // performance reasons
                 if !generics.is_empty() && !enum_ty.could_unify_with_deeply(db, goal) {
                     return None;
                 }
 
+                // Ignore types that have something to do with lifetimes
+                if enum_ty.contains_reference(db) {
+                    return None;
+                }
+
                 // Early exit if some param cannot be filled from lookup
                 let param_trees: Vec<Vec<TypeTree>> = variant
                     .fields(db)
@@ -203,33 +234,64 @@ pub(super) fn type_constructor<'a>(
                 Some(trees)
             }
             ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => {
-                let generics = db.generic_params(it.id.into());
+                // Ignore unstable
+                if it.is_unstable(db) {
+                    return None;
+                }
+
+                let generics = GenericDef::from(*it);
 
                 // Ignore enums with const generics
-                if generics
-                    .type_or_consts
-                    .values()
-                    .any(|it| matches!(it, TypeOrConstParamData::ConstParamData(_)))
-                {
+                if !generics.const_params(db).is_empty() {
                     return None;
                 }
 
                 // We currently do not check lifetime bounds so ignore all types that have something to do
                 // with them
-                if !generics.lifetimes.is_empty() {
+                if !generics.lifetime_params(db).is_empty() {
+                    return None;
+                }
+
+                let type_params = generics.type_params(db);
+
+                // Only account for stable type parameters for now, unstable params can be default
+                // tho, for example in `Box<T, #[unstable] A: Allocator>`
+                if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
                     return None;
                 }
 
+                let non_default_type_params_len =
+                    type_params.iter().filter(|it| it.default(db).is_none()).count();
+
                 let generic_params = lookup
                     .iter_types()
                     .collect::<Vec<_>>() // Force take ownership
                     .into_iter()
-                    .permutations(generics.type_or_consts.len());
+                    .permutations(non_default_type_params_len);
 
                 let trees = generic_params
                     .filter_map(|generics| {
+                        // Insert default type params
+                        let mut g = generics.into_iter();
+                        let generics: Vec<_> = type_params
+                            .iter()
+                            .map(|it| match it.default(db) {
+                                Some(ty) => ty,
+                                None => g.next().expect("Missing type param"),
+                            })
+                            .collect();
                         let struct_ty = it.ty_with_generics(db, generics.iter().cloned());
-                        if !generics.is_empty() && !struct_ty.could_unify_with_deeply(db, goal) {
+
+                        // Allow types with generics only if they take us straight to goal for
+                        // performance reasons
+                        if non_default_type_params_len != 0
+                            && struct_ty.could_unify_with_deeply(db, goal)
+                        {
+                            return None;
+                        }
+
+                        // Ignore types that have something to do with lifetimes
+                        if struct_ty.contains_reference(db) {
                             return None;
                         }
                         let fileds = it.fields(db);
@@ -301,20 +363,31 @@ pub(super) fn free_function<'a>(
     defs.iter()
         .filter_map(|def| match def {
             ScopeDef::ModuleDef(ModuleDef::Function(it)) => {
-                let generics = db.generic_params(it.id.into());
+                let generics = GenericDef::from(*it);
 
                 // Skip functions that require const generics
-                if generics
-                    .type_or_consts
-                    .values()
-                    .any(|it| matches!(it, TypeOrConstParamData::ConstParamData(_)))
-                {
+                if !generics.const_params(db).is_empty() {
                     return None;
                 }
 
-                // Ignore bigger number of generics for now as they kill the performance
                 // Ignore lifetimes as we do not check them
-                if generics.type_or_consts.len() > 0 || !generics.lifetimes.is_empty() {
+                if !generics.lifetime_params(db).is_empty() {
+                    return None;
+                }
+
+                let type_params = generics.type_params(db);
+
+                // Only account for stable type parameters for now, unstable params can be default
+                // tho, for example in `Box<T, #[unstable] A: Allocator>`
+                if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) {
+                    return None;
+                }
+
+                let non_default_type_params_len =
+                    type_params.iter().filter(|it| it.default(db).is_none()).count();
+
+                // Ignore bigger number of generics for now as they kill the performance
+                if non_default_type_params_len > 0 {
                     return None;
                 }
 
@@ -322,16 +395,26 @@ pub(super) fn free_function<'a>(
                     .iter_types()
                     .collect::<Vec<_>>() // Force take ownership
                     .into_iter()
-                    .permutations(generics.type_or_consts.len());
+                    .permutations(non_default_type_params_len);
 
                 let trees: Vec<_> = generic_params
                     .filter_map(|generics| {
+                        // Insert default type params
+                        let mut g = generics.into_iter();
+                        let generics: Vec<_> = type_params
+                            .iter()
+                            .map(|it| match it.default(db) {
+                                Some(ty) => ty,
+                                None => g.next().expect("Missing type param"),
+                            })
+                            .collect();
+
                         let ret_ty = it.ret_type_with_generics(db, generics.iter().cloned());
                         // Filter out private and unsafe functions
                         if !it.is_visible_from(db, *module)
                             || it.is_unsafe_to_call(db)
                             || it.is_unstable(db)
-                            || ret_ty.is_reference()
+                            || ret_ty.contains_reference(db)
                             || ret_ty.is_raw_ptr()
                         {
                             return None;
@@ -417,24 +500,17 @@ pub(super) fn impl_method<'a>(
             _ => None,
         })
         .filter_map(|(imp, ty, it)| {
-            let fn_generics = db.generic_params(it.id.into());
-            let imp_generics = db.generic_params(imp.id.into());
+            let fn_generics = GenericDef::from(it);
+            let imp_generics = GenericDef::from(imp);
 
             // Ignore impl if it has const type arguments
-            if fn_generics
-                .type_or_consts
-                .values()
-                .any(|it| matches!(it, TypeOrConstParamData::ConstParamData(_)))
-                || imp_generics
-                    .type_or_consts
-                    .values()
-                    .any(|it| matches!(it, TypeOrConstParamData::ConstParamData(_)))
+            if !fn_generics.const_params(db).is_empty() || !imp_generics.const_params(db).is_empty()
             {
                 return None;
             }
 
             // Ignore all functions that have something to do with lifetimes as we don't check them
-            if !fn_generics.lifetimes.is_empty() {
+            if !fn_generics.lifetime_params(db).is_empty() {
                 return None;
             }
 
@@ -448,8 +524,25 @@ pub(super) fn impl_method<'a>(
                 return None;
             }
 
+            let imp_type_params = imp_generics.type_params(db);
+            let fn_type_params = fn_generics.type_params(db);
+
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+            {
+                return None;
+            }
+
+            let non_default_type_params_len = imp_type_params
+                .iter()
+                .chain(fn_type_params.iter())
+                .filter(|it| it.default(db).is_none())
+                .count();
+
             // Ignore bigger number of generics for now as they kill the performance
-            if imp_generics.type_or_consts.len() + fn_generics.type_or_consts.len() > 0 {
+            if non_default_type_params_len > 0 {
                 return None;
             }
 
@@ -457,16 +550,27 @@ pub(super) fn impl_method<'a>(
                 .iter_types()
                 .collect::<Vec<_>>() // Force take ownership
                 .into_iter()
-                .permutations(imp_generics.type_or_consts.len() + fn_generics.type_or_consts.len());
+                .permutations(non_default_type_params_len);
 
             let trees: Vec<_> = generic_params
                 .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = imp_type_params
+                        .iter()
+                        .chain(fn_type_params.iter())
+                        .map(|it| match it.default(db) {
+                            Some(ty) => ty,
+                            None => g.next().expect("Missing type param"),
+                        })
+                        .collect();
+
                     let ret_ty = it.ret_type_with_generics(
                         db,
                         ty.type_arguments().chain(generics.iter().cloned()),
                     );
                     // Filter out functions that return references
-                    if ret_ty.is_reference() || ret_ty.is_raw_ptr() {
+                    if ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() {
                         return None;
                     }
 
@@ -590,3 +694,157 @@ pub(super) fn famous_types<'a>(
     })
     .filter(|tt| tt.ty(db).could_unify_with_deeply(db, goal))
 }
+
+/// # Impl static method (without self type) tactic
+///
+/// Attempts different functions from impl blocks that take no self parameter.
+///
+/// Updates lookup by new types reached and returns iterator that yields
+/// elements that unify with `goal`.
+///
+/// # Arguments
+/// * `db` - HIR database
+/// * `module` - Module where the term search target location
+/// * `defs` - Set of items in scope at term search target location
+/// * `lookup` - Lookup table for types
+/// * `goal` - Term search target type
+pub(super) fn impl_static_method<'a>(
+    db: &'a dyn HirDatabase,
+    module: &'a Module,
+    _defs: &'a FxHashSet<ScopeDef>,
+    lookup: &'a mut LookupTable,
+    goal: &'a Type,
+) -> impl Iterator<Item = TypeTree> + 'a {
+    lookup
+        .take_types_wishlist()
+        .into_iter()
+        .chain(iter::once(goal.clone()))
+        .flat_map(|ty| {
+            Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
+        })
+        .filter(|(_, imp)| !imp.is_unsafe(db))
+        .flat_map(|(ty, imp)| imp.items(db).into_iter().map(move |item| (imp, ty.clone(), item)))
+        .filter_map(|(imp, ty, it)| match it {
+            AssocItem::Function(f) => Some((imp, ty, f)),
+            _ => None,
+        })
+        .filter_map(|(imp, ty, it)| {
+            let fn_generics = GenericDef::from(it);
+            let imp_generics = GenericDef::from(imp);
+
+            // Ignore impl if it has const type arguments
+            if !fn_generics.const_params(db).is_empty() || !imp_generics.const_params(db).is_empty()
+            {
+                return None;
+            }
+
+            // Ignore all functions that have something to do with lifetimes as we don't check them
+            if !fn_generics.lifetime_params(db).is_empty()
+                || !imp_generics.lifetime_params(db).is_empty()
+            {
+                return None;
+            }
+
+            // Ignore functions with self param
+            if it.has_self_param(db) {
+                return None;
+            }
+
+            // Filter out private and unsafe functions
+            if !it.is_visible_from(db, *module) || it.is_unsafe_to_call(db) || it.is_unstable(db) {
+                return None;
+            }
+
+            let imp_type_params = imp_generics.type_params(db);
+            let fn_type_params = fn_generics.type_params(db);
+
+            // Only account for stable type parameters for now, unstable params can be default
+            // tho, for example in `Box<T, #[unstable] A: Allocator>`
+            if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+                || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
+            {
+                return None;
+            }
+
+            let non_default_type_params_len = imp_type_params
+                .iter()
+                .chain(fn_type_params.iter())
+                .filter(|it| it.default(db).is_none())
+                .count();
+
+            // Ignore bigger number of generics for now as they kill the performance
+            if non_default_type_params_len > 0 {
+                return None;
+            }
+
+            let generic_params = lookup
+                .iter_types()
+                .collect::<Vec<_>>() // Force take ownership
+                .into_iter()
+                .permutations(non_default_type_params_len);
+
+            let trees: Vec<_> = generic_params
+                .filter_map(|generics| {
+                    // Insert default type params
+                    let mut g = generics.into_iter();
+                    let generics: Vec<_> = imp_type_params
+                        .iter()
+                        .chain(fn_type_params.iter())
+                        .map(|it| match it.default(db) {
+                            Some(ty) => ty,
+                            None => g.next().expect("Missing type param"),
+                        })
+                        .collect();
+
+                    let ret_ty = it.ret_type_with_generics(
+                        db,
+                        ty.type_arguments().chain(generics.iter().cloned()),
+                    );
+                    // Filter out functions that return references
+                    if ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() {
+                        return None;
+                    }
+
+                    // Ignore functions that do not change the type
+                    // if ty.could_unify_with_deeply(db, &ret_ty) {
+                    //     return None;
+                    // }
+
+                    // Early exit if some param cannot be filled from lookup
+                    let param_trees: Vec<Vec<TypeTree>> = it
+                        .params_without_self_with_generics(
+                            db,
+                            ty.type_arguments().chain(generics.iter().cloned()),
+                        )
+                        .into_iter()
+                        .map(|field| lookup.find_autoref(db, &field.ty()))
+                        .collect::<Option<_>>()?;
+
+                    // Note that we need special case for 0 param constructors because of multi cartesian
+                    // product
+                    let fn_trees: Vec<TypeTree> = if param_trees.is_empty() {
+                        vec![TypeTree::Function { func: it, generics, params: Vec::new() }]
+                    } else {
+                        param_trees
+                            .into_iter()
+                            .multi_cartesian_product()
+                            .take(MAX_VARIATIONS)
+                            .map(|params| TypeTree::Function {
+                                func: it,
+                                generics: generics.clone(),
+
+                                params,
+                            })
+                            .collect()
+                    };
+
+                    lookup.insert(ret_ty.clone(), fn_trees.iter().cloned());
+                    Some((ret_ty, fn_trees))
+                })
+                .collect();
+            Some(trees)
+        })
+        .flatten()
+        .filter_map(|(ty, trees)| ty.could_unify_with_deeply(db, goal).then(|| trees))
+        .flatten()
+}
diff --git a/crates/hir/src/term_search/type_tree.rs b/crates/hir/src/term_search/type_tree.rs
index 4178ba2d7df..3cb2fcdd64b 100644
--- a/crates/hir/src/term_search/type_tree.rs
+++ b/crates/hir/src/term_search/type_tree.rs
@@ -1,16 +1,18 @@
 //! Type tree for term search
 
 use hir_def::find_path::PrefixKind;
+use hir_expand::mod_path::ModPath;
 use hir_ty::{db::HirDatabase, display::HirDisplay};
 use itertools::Itertools;
 
 use crate::{
-    Adt, AsAssocItem, Const, ConstParam, Field, Function, Local, ModuleDef, SemanticsScope, Static,
-    Struct, StructKind, Trait, Type, Variant,
+    Adt, AsAssocItem, Const, ConstParam, Field, Function, GenericDef, Local, ModuleDef,
+    SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
 };
 
-/// Helper function to prefix items with modules when required
-fn mod_item_path(db: &dyn HirDatabase, sema_scope: &SemanticsScope<'_>, def: &ModuleDef) -> String {
+/// Helper function to get path to `ModuleDef`
+fn mod_item_path(sema_scope: &SemanticsScope<'_>, def: &ModuleDef) -> Option<ModPath> {
+    let db = sema_scope.db;
     // Account for locals shadowing items from module
     let name_hit_count = def.name(db).map(|def_name| {
         let mut name_hit_count = 0;
@@ -23,12 +25,45 @@ fn mod_item_path(db: &dyn HirDatabase, sema_scope: &SemanticsScope<'_>, def: &Mo
     });
 
     let m = sema_scope.module();
-    let path = match name_hit_count {
+    match name_hit_count {
         Some(0..=1) | None => m.find_use_path(db.upcast(), *def, false, true),
         Some(_) => m.find_use_path_prefixed(db.upcast(), *def, PrefixKind::ByCrate, false, true),
-    };
+    }
+}
+
+/// Helper function to get path to `ModuleDef` as string
+fn mod_item_path_str(sema_scope: &SemanticsScope<'_>, def: &ModuleDef) -> String {
+    let path = mod_item_path(sema_scope, def);
+    path.map(|it| it.display(sema_scope.db.upcast()).to_string()).unwrap()
+}
+
+/// Helper function to get path to `Type`
+fn type_path(sema_scope: &SemanticsScope<'_>, ty: &Type) -> String {
+    let db = sema_scope.db;
+    match ty.as_adt() {
+        Some(adt) => {
+            let ty_name = ty.display(db).to_string();
+
+            let mut path = mod_item_path(sema_scope, &ModuleDef::Adt(adt)).unwrap();
+            path.pop_segment();
+            let path = path.display(db.upcast()).to_string();
+            match path.is_empty() {
+                true => ty_name,
+                false => format!("{path}::{ty_name}"),
+            }
+        }
+        None => ty.display(db).to_string(),
+    }
+}
 
-    path.map(|it| it.display(db.upcast()).to_string()).expect("use path error")
+/// Helper function to filter out generic parameters that are default
+fn non_default_generics(db: &dyn HirDatabase, def: GenericDef, generics: &[Type]) -> Vec<Type> {
+    def.type_params(db)
+        .into_iter()
+        .zip(generics)
+        .filter(|(tp, arg)| tp.default(db).as_ref() != Some(arg))
+        .map(|(_, arg)| arg.clone())
+        .collect()
 }
 
 /// Type tree shows how can we get from set of types to some type.
@@ -85,8 +120,8 @@ impl TypeTree {
     pub fn gen_source_code(&self, sema_scope: &SemanticsScope<'_>) -> String {
         let db = sema_scope.db;
         match self {
-            TypeTree::Const(it) => mod_item_path(db, sema_scope, &ModuleDef::Const(*it)),
-            TypeTree::Static(it) => mod_item_path(db, sema_scope, &ModuleDef::Static(*it)),
+            TypeTree::Const(it) => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
+            TypeTree::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
             TypeTree::Local(it) => return it.name(db).display(db.upcast()).to_string(),
             TypeTree::ConstParam(it) => return it.name(db).display(db.upcast()).to_string(),
             TypeTree::FamousType { value, .. } => return value.to_string(),
@@ -100,7 +135,7 @@ impl TypeTree {
                     match func.as_assoc_item(db).unwrap().containing_trait_or_trait_impl(db) {
                         Some(trait_) => {
                             let trait_name =
-                                mod_item_path(db, sema_scope, &ModuleDef::Trait(trait_));
+                                mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_));
                             let target = match self_param.access(db) {
                                 crate::Access::Shared => format!("&{target}"),
                                 crate::Access::Exclusive => format!("&mut {target}"),
@@ -116,15 +151,51 @@ impl TypeTree {
                 } else {
                     let args = params.iter().map(|f| f.gen_source_code(sema_scope)).join(", ");
 
-                    let fn_name = mod_item_path(db, sema_scope, &ModuleDef::Function(*func));
-                    format!("{fn_name}({args})",)
+                    match func.as_assoc_item(db).map(|it| it.container(db)) {
+                        Some(container) => {
+                            let container_name = match container {
+                                crate::AssocItemContainer::Trait(trait_) => {
+                                    mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))
+                                }
+                                crate::AssocItemContainer::Impl(imp) => {
+                                    let self_ty = imp.self_ty(db);
+                                    // Should it be guaranteed that `mod_item_path` always exists?
+                                    match self_ty
+                                        .as_adt()
+                                        .and_then(|adt| mod_item_path(sema_scope, &adt.into()))
+                                    {
+                                        Some(path) => {
+                                            path.display(sema_scope.db.upcast()).to_string()
+                                        }
+                                        None => self_ty.display(db).to_string(),
+                                    }
+                                }
+                            };
+                            let fn_name = func.name(db).display(db.upcast()).to_string();
+                            format!("{container_name}::{fn_name}({args})",)
+                        }
+                        None => {
+                            let fn_name =
+                                mod_item_path_str(sema_scope, &ModuleDef::Function(*func));
+                            format!("{fn_name}({args})",)
+                        }
+                    }
                 }
             }
             TypeTree::Variant { variant, generics, params } => {
+                let generics = non_default_generics(db, (*variant).into(), generics);
+                let generics_str = match generics.is_empty() {
+                    true => String::new(),
+                    false => {
+                        let generics =
+                            generics.iter().map(|it| type_path(sema_scope, it)).join(", ");
+                        format!("::<{generics}>")
+                    }
+                };
                 let inner = match variant.kind(db) {
                     StructKind::Tuple => {
                         let args = params.iter().map(|f| f.gen_source_code(sema_scope)).join(", ");
-                        format!("({args})")
+                        format!("{generics_str}({args})")
                     }
                     StructKind::Record => {
                         let fields = variant.fields(db);
@@ -139,21 +210,16 @@ impl TypeTree {
                                 )
                             })
                             .join(", ");
-                        format!("{{ {args} }}")
+                        format!("{generics_str}{{ {args} }}")
                     }
-                    StructKind::Unit => match generics.is_empty() {
-                        true => String::new(),
-                        false => {
-                            let generics = generics.iter().map(|it| it.display(db)).join(", ");
-                            format!("::<{generics}>")
-                        }
-                    },
+                    StructKind::Unit => generics_str,
                 };
 
-                let prefix = mod_item_path(db, sema_scope, &ModuleDef::Variant(*variant));
+                let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant));
                 format!("{prefix}{inner}")
             }
             TypeTree::Struct { strukt, generics, params } => {
+                let generics = non_default_generics(db, (*strukt).into(), generics);
                 let inner = match strukt.kind(db) {
                     StructKind::Tuple => {
                         let args = params.iter().map(|a| a.gen_source_code(sema_scope)).join(", ");
@@ -177,13 +243,14 @@ impl TypeTree {
                     StructKind::Unit => match generics.is_empty() {
                         true => String::new(),
                         false => {
-                            let generics = generics.iter().map(|it| it.display(db)).join(", ");
+                            let generics =
+                                generics.iter().map(|it| type_path(sema_scope, it)).join(", ");
                             format!("::<{generics}>")
                         }
                     },
                 };
 
-                let prefix = mod_item_path(db, sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)));
+                let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)));
                 format!("{prefix}{inner}")
             }
             TypeTree::Field { type_tree, field } => {
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index 3c4c4eed011..a32e36b7127 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -91,7 +91,7 @@ mod tests {
             fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#,
             r#"macro_rules! todo { () => (_) };
             enum Option<T> { Some(T), None }
-            fn f() { let a: i32 = 1; let b: Option<i32> = Option::None::<i32>; }"#,
+            fn f() { let a: i32 = 1; let b: Option<i32> = Option::None; }"#,
         )
     }
 
@@ -109,6 +109,42 @@ mod tests {
     }
 
     #[test]
+    fn test_enum_with_generics3() {
+        check_assist(
+            term_search,
+            r#"macro_rules! todo { () => (_) };
+            enum Option<T> { None, Some(T) }
+            fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = todo$0!(); }"#,
+            r#"macro_rules! todo { () => (_) };
+            enum Option<T> { None, Some(T) }
+            fn f() { let a: Option<i32> = Option::None; let b: Option<Option<i32>> = Option::Some(a); }"#,
+        )
+    }
+
+    #[test]
+    fn test_enum_with_generics4() {
+        check_assist(
+            term_search,
+            r#"macro_rules! todo { () => (_) };
+            enum Foo<T = i32> { Foo(T) }
+            fn f() { let a = 0; let b: Foo = todo$0!(); }"#,
+            r#"macro_rules! todo { () => (_) };
+            enum Foo<T = i32> { Foo(T) }
+            fn f() { let a = 0; let b: Foo = Foo::Foo(a); }"#,
+        );
+
+        check_assist(
+            term_search,
+            r#"macro_rules! todo { () => (_) };
+            enum Foo<T = i32> { Foo(T) }
+            fn f() { let a: Foo<u32> = Foo::Foo(0); let b: Foo<u32> = todo$0!(); }"#,
+            r#"macro_rules! todo { () => (_) };
+            enum Foo<T = i32> { Foo(T) }
+            fn f() { let a: Foo<u32> = Foo::Foo(0); let b: Foo<u32> = a; }"#,
+        )
+    }
+
+    #[test]
     fn test_newtype() {
         check_assist(
             term_search,
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index 3862acc2af4..7e1811b4cac 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -148,7 +148,7 @@ impl<'a> PathTransform<'a> {
         let mut defaulted_params: Vec<DefaultedParam> = Default::default();
         self.generic_def
             .into_iter()
-            .flat_map(|it| it.type_params(db))
+            .flat_map(|it| it.type_or_const_params(db))
             .skip(skip)
             // The actual list of trait type parameters may be longer than the one
             // used in the `impl` block due to trailing default type parameters.
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index bca08f91c1e..2ca93b5ca89 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -439,17 +439,18 @@ impl flags::AnalysisStats {
                                 if let Some(mut err_idx) = err.find("error[E") {
                                     err_idx += 7;
                                     let err_code = &err[err_idx..err_idx + 4];
-                                    // if err_code == "0308" {
-                                    println!("{}", err);
-                                    println!("{}", generated);
-                                    // }
+                                    if err_code == "0282" {
+                                        continue; // Byproduct of testing method
+                                    }
+                                    bar.println(err);
+                                    bar.println(generated);
                                     acc.error_codes
                                         .entry(err_code.to_owned())
                                         .and_modify(|n| *n += 1)
                                         .or_insert(1);
                                 } else {
                                     acc.syntax_errors += 1;
-                                    bar.println(format!("Syntax error here >>>>\n{}", err));
+                                    bar.println(format!("Syntax error: \n{}", err));
                                 }
                             }
                         }