diff options
author | Matthew Hall <[email protected]> | 2020-04-02 18:42:30 +0100 |
---|---|---|
committer | Matthew Hall <[email protected]> | 2020-04-02 18:42:30 +0100 |
commit | 6a2127be28a837215801f4ac3cd7d46ef7c4485b (patch) | |
tree | 2bacfb7f92c7059a5975fd5f256122b08190f93d /crates | |
parent | 1fee60181fea56ebe6b5e4aeb11cf9df25a1d087 (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.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 54 |
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 @@ | |||
1 | use hir::ImplDef; | ||
2 | use ra_syntax::{ | 1 | use 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 | ||
196 | pub trait From<T> { | 184 | pub 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 | ||
213 | pub trait From<T> { | 201 | pub 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 | }; |
24 | use hir_ty::{ | 24 | use 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 | }; |
28 | use ra_db::{CrateId, Edition, FileId}; | 28 | use ra_db::{CrateId, Edition, FileId}; |
29 | use ra_prof::profile; | 29 | use 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) |