Check receiver type properly

This commit is contained in:
Florian Diebold 2019-12-01 22:14:28 +01:00
parent 599dab5982
commit 456d52fdfa
4 changed files with 80 additions and 19 deletions

View File

@ -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 })

View File

@ -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

View File

@ -167,13 +167,19 @@ impl<T> Canonicalized<T> {
}
}
pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Substs {
pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option<Substs> {
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 {

View File

@ -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<T>(
name: Option<&Name>,
mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
) -> Option<T> {
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<T>(
// 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<T>(
mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
) -> Option<T> {
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
}