Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/term_search/tactics.rs')
-rw-r--r--crates/hir/src/term_search/tactics.rs162
1 files changed, 92 insertions, 70 deletions
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index 012d815394..666d63ac15 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -16,7 +16,7 @@ use rustc_hash::FxHashSet;
use crate::{
Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type,
- Variant,
+ TypeParam, Variant,
};
use crate::term_search::{Expr, TermSearchConfig};
@@ -82,7 +82,7 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
return None;
}
- ty.could_unify_with_deeply(db, &ctx.goal).then(|| expr)
+ ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr)
})
}
@@ -118,11 +118,15 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
}
let generics = GenericDef::from(variant.parent_enum(db));
-
- // Ignore enums with const generics
- if !generics.const_params(db).is_empty() {
+ let Some(type_params) = generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()
+ else {
+ // Ignore enums with const generics
return Vec::new();
- }
+ };
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
@@ -130,9 +134,6 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
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()) {
@@ -154,13 +155,10 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
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"),
- })
+ .map(|it| it.default(db).unwrap_or_else(|| g.next().expect("No generic")))
.collect();
- let enum_ty = parent_enum.ty_with_args(db, generics.iter().cloned());
+ let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned());
// Allow types with generics only if they take us straight to goal for
// performance reasons
@@ -212,9 +210,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let exprs: Vec<(Type, Vec<Expr>)> = enum_
.variants(db)
.into_iter()
- .flat_map(|it| {
- variant_helper(db, lookup, enum_.clone(), it, &ctx.goal, &ctx.config)
- })
+ .flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.goal, &ctx.config))
.collect();
if !exprs.is_empty() {
@@ -231,10 +227,12 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let generics = GenericDef::from(*it);
- // Ignore enums with const generics
- if !generics.const_params(db).is_empty() {
- return None;
- }
+ // Ignore const params for now
+ let type_params = generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
// We currently do not check lifetime bounds so ignore all types that have something to do
// with them
@@ -242,8 +240,6 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
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()) {
@@ -265,12 +261,13 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
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"),
+ .map(|it| {
+ it.default(db)
+ .unwrap_or_else(|| g.next().expect("Missing type param"))
})
.collect();
- let struct_ty = it.ty_with_args(db, generics.iter().cloned());
+
+ let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned());
// Allow types with generics only if they take us straight to goal for
// performance reasons
@@ -324,7 +321,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
_ => None,
})
.flatten()
- .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
+ .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@@ -352,18 +349,18 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
ScopeDef::ModuleDef(ModuleDef::Function(it)) => {
let generics = GenericDef::from(*it);
- // Skip functions that require const generics
- if !generics.const_params(db).is_empty() {
- return None;
- }
+ // Ignore const params for now
+ let type_params = generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
// Ignore lifetimes as we do not check them
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()) {
@@ -391,10 +388,14 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
let generics: Vec<_> = type_params
.iter()
.map(|it| match it.default(db) {
- Some(ty) => ty,
- None => g.next().expect("Missing type param"),
+ Some(ty) => Some(ty),
+ None => {
+ let generic = g.next().expect("Missing type param");
+ // Filter out generics that do not unify due to trait bounds
+ it.ty(db).could_unify_with(db, &generic).then_some(generic)
+ }
})
- .collect();
+ .collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(db, generics.iter().cloned());
// Filter out private and unsafe functions
@@ -409,13 +410,13 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
- .params_without_self_with_generics(db, generics.iter().cloned())
+ .params_without_self_with_args(db, generics.iter().cloned())
.into_iter()
.map(|field| {
let ty = field.ty();
match ty.is_mutable_reference() {
true => None,
- false => lookup.find_autoref(db, &ty),
+ false => lookup.find_autoref(db, ty),
}
})
.collect::<Option<_>>()?;
@@ -447,7 +448,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
_ => None,
})
.flatten()
- .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
+ .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@@ -487,11 +488,19 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
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 const params for now
+ let imp_type_params = imp_generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
+
+ // Ignore const params for now
+ let fn_type_params = fn_generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty() {
@@ -508,9 +517,6 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
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())
@@ -544,10 +550,14 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
.iter()
.chain(fn_type_params.iter())
.map(|it| match it.default(db) {
- Some(ty) => ty,
- None => g.next().expect("Missing type param"),
+ Some(ty) => Some(ty),
+ None => {
+ let generic = g.next().expect("Missing type param");
+ // Filter out generics that do not unify due to trait bounds
+ it.ty(db).could_unify_with(db, &generic).then_some(generic)
+ }
})
- .collect();
+ .collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
@@ -579,16 +589,16 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
- .params_without_self_with_generics(
+ .params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
- .map(|field| lookup.find_autoref(db, &field.ty()))
+ .map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
- .chain(param_exprs.into_iter())
+ .chain(param_exprs)
.multi_cartesian_product()
.map(|params| {
let mut params = params.into_iter();
@@ -609,7 +619,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
Some(exprs)
})
.flatten()
- .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
+ .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@@ -647,7 +657,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
Some((filed_ty, exprs))
})
})
- .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
+ .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}
@@ -719,11 +729,19 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
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 const params for now
+ let imp_type_params = imp_generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
+
+ // Ignore const params for now
+ let fn_type_params = fn_generics
+ .type_or_const_params(db)
+ .into_iter()
+ .map(|it| it.as_type_param(db))
+ .collect::<Option<Vec<TypeParam>>>()?;
// Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty()
@@ -742,9 +760,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
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())
@@ -778,10 +793,17 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.iter()
.chain(fn_type_params.iter())
.map(|it| match it.default(db) {
- Some(ty) => ty,
- None => g.next().expect("Missing type param"),
+ Some(ty) => Some(ty),
+ None => {
+ let generic = g.next().expect("Missing type param");
+ it.trait_bounds(db)
+ .into_iter()
+ .all(|bound| generic.impls_trait(db, bound, &[]));
+ // Filter out generics that do not unify due to trait bounds
+ it.ty(db).could_unify_with(db, &generic).then_some(generic)
+ }
})
- .collect();
+ .collect::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
@@ -801,12 +823,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it
- .params_without_self_with_generics(
+ .params_without_self_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter()
- .map(|field| lookup.find_autoref(db, &field.ty()))
+ .map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?;
// Note that we need special case for 0 param constructors because of multi cartesian
@@ -832,6 +854,6 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
Some(exprs)
})
.flatten()
- .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then(|| exprs))
+ .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten()
}