mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +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::{
|
use ra_syntax::{
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner},
|
||||||
TextUnit,
|
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 var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
|
||||||
|
|
||||||
let krate = match scope.module() {
|
e_ty.impls_trait(sema.db, from_trait, &[var_ty.clone()])
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -192,7 +180,7 @@ impl From<String> for A {
|
||||||
A::Two(v)
|
A::Two(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait From<T> {
|
pub trait From<T> {
|
||||||
fn from(T) -> Self;
|
fn from(T) -> Self;
|
||||||
}"#,
|
}"#,
|
||||||
|
@ -209,7 +197,7 @@ impl From<String> for A {
|
||||||
A::Two(v)
|
A::Two(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait From<T> {
|
pub trait From<T> {
|
||||||
fn from(T) -> Self;
|
fn from(T) -> Self;
|
||||||
}"#,
|
}"#,
|
||||||
|
|
|
@ -23,7 +23,7 @@ use hir_expand::{
|
||||||
};
|
};
|
||||||
use hir_ty::{
|
use hir_ty::{
|
||||||
autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
|
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_db::{CrateId, Edition, FileId};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
|
@ -960,38 +960,6 @@ impl ImplDef {
|
||||||
db.impl_data(self.id).target_trait.clone()
|
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 {
|
pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef {
|
||||||
db.impl_data(self.id).target_type.clone()
|
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.
|
// FIXME: this method is broken, as it doesn't take closures into account.
|
||||||
pub fn as_callable(&self) -> Option<CallableDef> {
|
pub fn as_callable(&self) -> Option<CallableDef> {
|
||||||
Some(self.ty.value.as_callable()?.0)
|
Some(self.ty.value.as_callable()?.0)
|
||||||
|
|
Loading…
Reference in a new issue