From 456d52fdfa8525af2a54e76ee5300f0a40ef582a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 1 Dec 2019 22:14:28 +0100 Subject: Check receiver type properly --- crates/ra_hir_ty/src/infer.rs | 6 ++- crates/ra_hir_ty/src/infer/coerce.rs | 2 +- crates/ra_hir_ty/src/infer/unify.rs | 20 +++++---- crates/ra_hir_ty/src/method_resolution.rs | 71 +++++++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 81afbd2b4..0889a6bf9 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -36,11 +36,13 @@ use ra_prof::profile; use super::{ primitive::{FloatTy, IntTy}, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, - ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, - TypeWalk, Uncertain, + ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, + Uncertain, }; use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; +pub use unify::unify; + macro_rules! ty_app { ($ctor:pat, $param:pat) => { crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 9bfc701cd..9daa77cfa 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -10,7 +10,7 @@ use test_utils::tested_by; use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; -use super::{InEnvironment, InferTy, InferenceContext, unify::TypeVarValue}; +use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { /// Unify two types, but may coerce the first one to the second one diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index ff50138f5..8ed2a6090 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -167,13 +167,19 @@ impl Canonicalized { } } -pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Substs { +pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option { let mut table = InferenceTable::new(); - let vars = Substs::builder(ty1.num_vars) - .fill(std::iter::repeat_with(|| table.new_type_var())).build(); + let vars = + Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); - table.unify(&ty_with_vars, ty2); - Substs::builder(ty1.num_vars).fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))).build() + if !table.unify(&ty_with_vars, ty2) { + return None; + } + Some( + Substs::builder(ty1.num_vars) + .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) + .build(), + ) } #[derive(Clone, Debug)] @@ -183,9 +189,7 @@ pub(crate) struct InferenceTable { impl InferenceTable { pub fn new() -> Self { - InferenceTable { - var_unification_table: InPlaceUnificationTable::new(), - } + InferenceTable { var_unification_table: InPlaceUnificationTable::new() } } pub fn new_type_var(&mut self) -> Ty { diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index fbb932a3e..97281cf15 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -7,19 +7,20 @@ use std::sync::Arc; use arrayvec::ArrayVec; use hir_def::{ lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, - FunctionId, HasModule, ImplId, TraitId, + FunctionId, HasModule, ImplId, Lookup, TraitId, }; use hir_expand::name::Name; use ra_db::CrateId; use ra_prof::profile; use rustc_hash::FxHashMap; +use super::Substs; use crate::{ autoderef, db::HirDatabase, primitive::{FloatBitness, Uncertain}, utils::all_super_traits, - Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, + Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This is used as a key for indexing impls. @@ -231,21 +232,42 @@ fn iterate_method_candidates_autoref( name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { - if let Some(result) = iterate_method_candidates_by_receiver(&deref_chain[0], &deref_chain[1..], db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &deref_chain[0], + &deref_chain[1..], + db, + resolver, + name, + &mut callback, + ) { return Some(result); } let refed = Canonical { num_vars: deref_chain[0].num_vars, value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), }; - if let Some(result) = iterate_method_candidates_by_receiver(&refed, deref_chain, db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &refed, + deref_chain, + db, + resolver, + name, + &mut callback, + ) { return Some(result); } let ref_muted = Canonical { num_vars: deref_chain[0].num_vars, value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), }; - if let Some(result) = iterate_method_candidates_by_receiver(&ref_muted, deref_chain, db, resolver, name, &mut callback) { + if let Some(result) = iterate_method_candidates_by_receiver( + &ref_muted, + deref_chain, + db, + resolver, + name, + &mut callback, + ) { return Some(result); } None @@ -264,7 +286,14 @@ fn iterate_method_candidates_by_receiver( // be found in any of the derefs of receiver_ty, so we have to go through // that. for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { - if let Some(result) = iterate_method_candidates_inner(self_ty, db, resolver, name, Some(receiver_ty), &mut callback) { + if let Some(result) = iterate_method_candidates_inner( + self_ty, + db, + resolver, + name, + Some(receiver_ty), + &mut callback, + ) { return Some(result); } } @@ -280,7 +309,9 @@ fn iterate_method_candidates_inner( mut callback: impl FnMut(&Ty, AssocItemId) -> Option, ) -> Option { let krate = resolver.krate()?; - if let Some(result) = iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) { + if let Some(result) = + iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) + { return Some(result); } if let Some(result) = @@ -381,7 +412,31 @@ fn is_valid_candidate( if !data.has_self_param { return false; } - // TODO compare receiver ty + let substs = match m.lookup(db).container { + hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) + .push(self_ty.value.clone()) + .fill_with_unknown() + .build(), + hir_def::ContainerId::ImplId(impl_id) => { + let vars = + Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); + let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); + let self_ty_with_vars = + Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; + if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value) + { + substs + } else { + return false; + } + } + hir_def::ContainerId::ModuleId(_) => unreachable!(), + }; + let sig = db.callable_item_signature(m.into()); + let receiver = sig.params()[0].clone().subst(&substs); + if receiver != receiver_ty.value { + return false; + } } true } -- cgit v1.2.3