From 6a2127be28a837215801f4ac3cd7d46ef7c4485b Mon Sep 17 00:00:00 2001 From: Matthew Hall Date: Thu, 2 Apr 2020 18:42:30 +0100 Subject: Cleanup checking for existing impls in impl From assist Use the trait solver to check if there's an existing implementation of From for the enum. --- .../src/handlers/add_from_impl_for_enum.rs | 18 ++------ crates/ra_hir/src/code_model.rs | 54 +++++++++------------- 2 files changed, 24 insertions(+), 48 deletions(-) (limited to 'crates') 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 @@ -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 for A { A::Two(v) } } - + pub trait From { fn from(T) -> Self; }"#, @@ -209,7 +197,7 @@ impl From for A { A::Two(v) } } - + pub trait From { fn from(T) -> Self; }"#, 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::{ }; 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 { Some(self.ty.value.as_callable()?.0) -- cgit v1.2.3