Simplify impl_method tactic

This commit is contained in:
Tavo Annus 2024-06-22 14:22:56 +03:00
parent 23d3ac70e9
commit b4f3eb48db

View file

@ -438,6 +438,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
lookup lookup
.new_types(NewTypesKey::ImplMethod) .new_types(NewTypesKey::ImplMethod)
.into_iter() .into_iter()
.filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown()))
.filter(|_| should_continue())
.flat_map(|ty| { .flat_map(|ty| {
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp)) Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
}) })
@ -450,22 +452,10 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
let fn_generics = GenericDef::from(it); let fn_generics = GenericDef::from(it);
let imp_generics = GenericDef::from(imp); let imp_generics = GenericDef::from(imp);
// 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 // Ignore all functions that have something to do with lifetimes as we don't check them
if !fn_generics.lifetime_params(db).is_empty() { if !fn_generics.lifetime_params(db).is_empty()
|| !imp_generics.lifetime_params(db).is_empty()
{
return None; return None;
} }
@ -479,59 +469,15 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
return None; return None;
} }
// 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;
}
// Double check that we have fully known type
if ty.type_arguments().any(|it| it.contains_unknown()) {
return None;
}
let non_default_fn_type_params_len =
fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
// Ignore functions with generics for now as they kill the performance // Ignore functions with generics for now as they kill the performance
// Also checking bounds for generics is problematic // Also checking bounds for generics is problematic
if non_default_fn_type_params_len > 0 { if fn_generics.type_or_const_params(db).len() > 0 {
return None; return None;
} }
let generic_params = lookup let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
.iter_types()
.collect::<Vec<_>>() // Force take ownership
.into_iter()
.permutations(non_default_fn_type_params_len);
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
let generics: Vec<_> = ty
.type_arguments()
.map(Some)
.chain(fn_type_params.iter().map(|it| match it.default(db) {
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::<Option<_>>()?;
let ret_ty = it.ret_type_with_args(
db,
ty.type_arguments().chain(generics.iter().cloned()),
);
// Filter out functions that return references // Filter out functions that return references
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
|| ret_ty.is_raw_ptr()
{ {
return None; return None;
} }
@ -541,10 +487,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
return None; return None;
} }
let self_ty = it let self_ty =
.self_param(db) it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments());
.expect("No self param")
.ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
// Ignore functions that have different self type // Ignore functions that have different self type
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) { if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
@ -555,14 +499,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
// Early exit if some param cannot be filled from lookup // Early exit if some param cannot be filled from lookup
let param_exprs: Vec<Vec<Expr>> = it let param_exprs: Vec<Vec<Expr>> = it
.params_without_self_with_args( .params_without_self_with_args(db, ty.type_arguments())
db,
ty.type_arguments().chain(generics.iter().cloned()),
)
.into_iter() .into_iter()
.map(|field| lookup.find_autoref(db, field.ty())) .map(|field| lookup.find_autoref(db, field.ty()))
.collect::<Option<_>>()?; .collect::<Option<_>>()?;
let generics: Vec<_> = ty.type_arguments().collect();
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs) let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
.chain(param_exprs) .chain(param_exprs)
.multi_cartesian_product() .multi_cartesian_product()
@ -578,13 +520,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
}) })
.collect(); .collect();
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
Some((ret_ty, fn_exprs)) Some((ret_ty, fn_exprs))
}) })
.collect();
Some(exprs)
})
.flatten()
.filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs))
.flatten() .flatten()
} }