mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Cleanup checking for existing impls in impl From assist
Use the trait solver to check if there's an existing implementation of From<type_in_enum_variant> for the enum.
This commit is contained in:
parent
1fee60181f
commit
6a2127be28
2 changed files with 24 additions and 48 deletions
|
@ -1,4 +1,3 @@
|
|||
use hir::ImplDef;
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, NameOwner},
|
||||
TextUnit,
|
||||
|
@ -99,18 +98,7 @@ fn already_has_from_impl(
|
|||
};
|
||||
let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
|
||||
|
||||
let krate = match scope.module() {
|
||||
Some(s) => s.krate(),
|
||||
_ => return false,
|
||||
};
|
||||
let impls = ImplDef::for_trait(sema.db, krate, from_trait);
|
||||
let imp = impls.iter().find(|imp| {
|
||||
let targets_enum = imp.target_ty(sema.db) == e_ty;
|
||||
let param_matches = imp.target_trait_substs_matches(sema.db, &[var_ty.clone()]);
|
||||
targets_enum && param_matches
|
||||
});
|
||||
|
||||
imp.is_some()
|
||||
e_ty.impls_trait(sema.db, from_trait, &[var_ty.clone()])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -192,7 +180,7 @@ impl From<String> for A {
|
|||
A::Two(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait From<T> {
|
||||
fn from(T) -> Self;
|
||||
}"#,
|
||||
|
@ -209,7 +197,7 @@ impl From<String> for A {
|
|||
A::Two(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait From<T> {
|
||||
fn from(T) -> Self;
|
||||
}"#,
|
||||
|
|
|
@ -23,7 +23,7 @@ use hir_expand::{
|
|||
};
|
||||
use hir_ty::{
|
||||
autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
|
||||
Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
|
||||
Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
|
||||
};
|
||||
use ra_db::{CrateId, Edition, FileId};
|
||||
use ra_prof::profile;
|
||||
|
@ -960,38 +960,6 @@ impl ImplDef {
|
|||
db.impl_data(self.id).target_trait.clone()
|
||||
}
|
||||
|
||||
pub fn target_trait_substs_matches(&self, db: &dyn HirDatabase, typs: &[Type]) -> bool {
|
||||
let type_ref = match self.target_trait(db) {
|
||||
Some(typ_ref) => typ_ref,
|
||||
None => return false,
|
||||
};
|
||||
let resolver = self.id.resolver(db.upcast());
|
||||
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
|
||||
let ty = Ty::from_hir(&ctx, &type_ref);
|
||||
let d = match ty.dyn_trait_ref() {
|
||||
Some(d) => d,
|
||||
None => return false,
|
||||
};
|
||||
let mut matches = true;
|
||||
let mut i = 0;
|
||||
d.substs.walk(&mut |t| {
|
||||
if matches {
|
||||
if i >= typs.len() {
|
||||
matches = false;
|
||||
return;
|
||||
}
|
||||
match t {
|
||||
Ty::Bound(_) => matches = i == 0,
|
||||
_ => {
|
||||
matches = *t == typs[i].ty.value;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
matches
|
||||
}
|
||||
|
||||
pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef {
|
||||
db.impl_data(self.id).target_type.clone()
|
||||
}
|
||||
|
@ -1116,6 +1084,26 @@ impl Type {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
|
||||
let trait_ref = hir_ty::TraitRef {
|
||||
trait_: trait_.id,
|
||||
substs: Substs::build_for_def(db, trait_.id)
|
||||
.push(self.ty.value.clone())
|
||||
.fill(args.iter().map(|t| t.ty.value.clone()))
|
||||
.build(),
|
||||
};
|
||||
|
||||
let goal = Canonical {
|
||||
value: hir_ty::InEnvironment::new(
|
||||
self.ty.environment.clone(),
|
||||
hir_ty::Obligation::Trait(trait_ref),
|
||||
),
|
||||
num_vars: 0,
|
||||
};
|
||||
|
||||
db.trait_solve(self.krate, goal).is_some()
|
||||
}
|
||||
|
||||
// FIXME: this method is broken, as it doesn't take closures into account.
|
||||
pub fn as_callable(&self) -> Option<CallableDef> {
|
||||
Some(self.ty.value.as_callable()?.0)
|
||||
|
|
Loading…
Reference in a new issue