aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorMatthew Hall <[email protected]>2020-04-02 18:42:30 +0100
committerMatthew Hall <[email protected]>2020-04-02 18:42:30 +0100
commit6a2127be28a837215801f4ac3cd7d46ef7c4485b (patch)
tree2bacfb7f92c7059a5975fd5f256122b08190f93d /crates
parent1fee60181fea56ebe6b5e4aeb11cf9df25a1d087 (diff)
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.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs18
-rw-r--r--crates/ra_hir/src/code_model.rs54
2 files changed, 24 insertions, 48 deletions
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index cf94a214a..864373aa5 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,4 +1,3 @@
1use hir::ImplDef;
2use ra_syntax::{ 1use ra_syntax::{
3 ast::{self, AstNode, NameOwner}, 2 ast::{self, AstNode, NameOwner},
4 TextUnit, 3 TextUnit,
@@ -99,18 +98,7 @@ fn already_has_from_impl(
99 }; 98 };
100 let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db); 99 let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
101 100
102 let krate = match scope.module() { 101 e_ty.impls_trait(sema.db, from_trait, &[var_ty.clone()])
103 Some(s) => s.krate(),
104 _ => return false,
105 };
106 let impls = ImplDef::for_trait(sema.db, krate, from_trait);
107 let imp = impls.iter().find(|imp| {
108 let targets_enum = imp.target_ty(sema.db) == e_ty;
109 let param_matches = imp.target_trait_substs_matches(sema.db, &[var_ty.clone()]);
110 targets_enum && param_matches
111 });
112
113 imp.is_some()
114} 102}
115 103
116#[cfg(test)] 104#[cfg(test)]
@@ -192,7 +180,7 @@ impl From<String> for A {
192 A::Two(v) 180 A::Two(v)
193 } 181 }
194} 182}
195 183
196pub trait From<T> { 184pub trait From<T> {
197 fn from(T) -> Self; 185 fn from(T) -> Self;
198}"#, 186}"#,
@@ -209,7 +197,7 @@ impl From<String> for A {
209 A::Two(v) 197 A::Two(v)
210 } 198 }
211} 199}
212 200
213pub trait From<T> { 201pub trait From<T> {
214 fn from(T) -> Self; 202 fn from(T) -> Self;
215}"#, 203}"#,
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 3889a7e5a..c6f3bdb8e 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -23,7 +23,7 @@ use hir_expand::{
23}; 23};
24use hir_ty::{ 24use hir_ty::{
25 autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy, 25 autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
26 Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, 26 Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
27}; 27};
28use ra_db::{CrateId, Edition, FileId}; 28use ra_db::{CrateId, Edition, FileId};
29use ra_prof::profile; 29use ra_prof::profile;
@@ -960,38 +960,6 @@ impl ImplDef {
960 db.impl_data(self.id).target_trait.clone() 960 db.impl_data(self.id).target_trait.clone()
961 } 961 }
962 962
963 pub fn target_trait_substs_matches(&self, db: &dyn HirDatabase, typs: &[Type]) -> bool {
964 let type_ref = match self.target_trait(db) {
965 Some(typ_ref) => typ_ref,
966 None => return false,
967 };
968 let resolver = self.id.resolver(db.upcast());
969 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
970 let ty = Ty::from_hir(&ctx, &type_ref);
971 let d = match ty.dyn_trait_ref() {
972 Some(d) => d,
973 None => return false,
974 };
975 let mut matches = true;
976 let mut i = 0;
977 d.substs.walk(&mut |t| {
978 if matches {
979 if i >= typs.len() {
980 matches = false;
981 return;
982 }
983 match t {
984 Ty::Bound(_) => matches = i == 0,
985 _ => {
986 matches = *t == typs[i].ty.value;
987 i += 1;
988 }
989 }
990 }
991 });
992 matches
993 }
994
995 pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef { 963 pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef {
996 db.impl_data(self.id).target_type.clone() 964 db.impl_data(self.id).target_type.clone()
997 } 965 }
@@ -1116,6 +1084,26 @@ impl Type {
1116 ) 1084 )
1117 } 1085 }
1118 1086
1087 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1088 let trait_ref = hir_ty::TraitRef {
1089 trait_: trait_.id,
1090 substs: Substs::build_for_def(db, trait_.id)
1091 .push(self.ty.value.clone())
1092 .fill(args.iter().map(|t| t.ty.value.clone()))
1093 .build(),
1094 };
1095
1096 let goal = Canonical {
1097 value: hir_ty::InEnvironment::new(
1098 self.ty.environment.clone(),
1099 hir_ty::Obligation::Trait(trait_ref),
1100 ),
1101 num_vars: 0,
1102 };
1103
1104 db.trait_solve(self.krate, goal).is_some()
1105 }
1106
1119 // FIXME: this method is broken, as it doesn't take closures into account. 1107 // FIXME: this method is broken, as it doesn't take closures into account.
1120 pub fn as_callable(&self) -> Option<CallableDef> { 1108 pub fn as_callable(&self) -> Option<CallableDef> {
1121 Some(self.ty.value.as_callable()?.0) 1109 Some(self.ty.value.as_callable()?.0)