mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Simplify impl_method
tactic
This commit is contained in:
parent
23d3ac70e9
commit
b4f3eb48db
1 changed files with 41 additions and 104 deletions
|
@ -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,112 +469,59 @@ 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
|
// Ignore functions with generics for now as they kill the performance
|
||||||
// tho, for example in `Box<T, #[unstable] A: Allocator>`
|
// Also checking bounds for generics is problematic
|
||||||
if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
|
if fn_generics.type_or_const_params(db).len() > 0 {
|
||||||
|| fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none())
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret_ty = it.ret_type_with_args(db, ty.type_arguments());
|
||||||
|
// Filter out functions that return references
|
||||||
|
if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr()
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double check that we have fully known type
|
// Ignore functions that do not change the type
|
||||||
if ty.type_arguments().any(|it| it.contains_unknown()) {
|
if ty.could_unify_with_deeply(db, &ret_ty) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let non_default_fn_type_params_len =
|
let self_ty =
|
||||||
fn_type_params.iter().filter(|it| it.default(db).is_none()).count();
|
it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments());
|
||||||
|
|
||||||
// Ignore functions with generics for now as they kill the performance
|
// Ignore functions that have different self type
|
||||||
// Also checking bounds for generics is problematic
|
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
|
||||||
if non_default_fn_type_params_len > 0 {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let generic_params = lookup
|
let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
|
||||||
.iter_types()
|
|
||||||
.collect::<Vec<_>>() // Force take ownership
|
// Early exit if some param cannot be filled from lookup
|
||||||
|
let param_exprs: Vec<Vec<Expr>> = it
|
||||||
|
.params_without_self_with_args(db, ty.type_arguments())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.permutations(non_default_fn_type_params_len);
|
.map(|field| lookup.find_autoref(db, field.ty()))
|
||||||
|
.collect::<Option<_>>()?;
|
||||||
|
|
||||||
let exprs: Vec<_> = generic_params
|
let generics: Vec<_> = ty.type_arguments().collect();
|
||||||
.filter(|_| should_continue())
|
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
|
||||||
.filter_map(|generics| {
|
.chain(param_exprs)
|
||||||
// Insert default type params
|
.multi_cartesian_product()
|
||||||
let mut g = generics.into_iter();
|
.map(|params| {
|
||||||
let generics: Vec<_> = ty
|
let mut params = params.into_iter();
|
||||||
.type_arguments()
|
let target = Box::new(params.next().unwrap());
|
||||||
.map(Some)
|
Expr::Method {
|
||||||
.chain(fn_type_params.iter().map(|it| match it.default(db) {
|
func: it,
|
||||||
Some(ty) => Some(ty),
|
generics: generics.clone(),
|
||||||
None => {
|
target,
|
||||||
let generic = g.next().expect("Missing type param");
|
params: params.collect(),
|
||||||
// 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
|
|
||||||
if ctx.config.enable_borrowcheck && 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let self_ty = it
|
|
||||||
.self_param(db)
|
|
||||||
.expect("No self param")
|
|
||||||
.ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned()));
|
|
||||||
|
|
||||||
// Ignore functions that have different self type
|
|
||||||
if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
|
|
||||||
|
|
||||||
// Early exit if some param cannot be filled from lookup
|
|
||||||
let param_exprs: Vec<Vec<Expr>> = it
|
|
||||||
.params_without_self_with_args(
|
|
||||||
db,
|
|
||||||
ty.type_arguments().chain(generics.iter().cloned()),
|
|
||||||
)
|
|
||||||
.into_iter()
|
|
||||||
.map(|field| lookup.find_autoref(db, field.ty()))
|
|
||||||
.collect::<Option<_>>()?;
|
|
||||||
|
|
||||||
let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
|
|
||||||
.chain(param_exprs)
|
|
||||||
.multi_cartesian_product()
|
|
||||||
.map(|params| {
|
|
||||||
let mut params = params.into_iter();
|
|
||||||
let target = Box::new(params.next().unwrap());
|
|
||||||
Expr::Method {
|
|
||||||
func: it,
|
|
||||||
generics: generics.clone(),
|
|
||||||
target,
|
|
||||||
params: params.collect(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned());
|
|
||||||
Some((ret_ty, fn_exprs))
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Some(exprs)
|
|
||||||
|
Some((ret_ty, fn_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()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue