diff options
author | Florian Diebold <[email protected]> | 2019-12-01 21:14:28 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-02 18:33:13 +0000 |
commit | 456d52fdfa8525af2a54e76ee5300f0a40ef582a (patch) | |
tree | e8cd093624ac3ccc9926856dc8db0d4daa0d0b8a /crates/ra_hir_ty/src | |
parent | 599dab59824b164b1c24e2e51adeae1ac1307964 (diff) |
Check receiver type properly
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 71 |
4 files changed, 80 insertions, 19 deletions
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; | |||
36 | use super::{ | 36 | use super::{ |
37 | primitive::{FloatTy, IntTy}, | 37 | primitive::{FloatTy, IntTy}, |
38 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 38 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
39 | ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, | 39 | ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
40 | TypeWalk, Uncertain, | 40 | Uncertain, |
41 | }; | 41 | }; |
42 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; | 42 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; |
43 | 43 | ||
44 | pub use unify::unify; | ||
45 | |||
44 | macro_rules! ty_app { | 46 | macro_rules! ty_app { |
45 | ($ctor:pat, $param:pat) => { | 47 | ($ctor:pat, $param:pat) => { |
46 | crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) | 48 | 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; | |||
10 | 10 | ||
11 | use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; | 11 | use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; |
12 | 12 | ||
13 | use super::{InEnvironment, InferTy, InferenceContext, unify::TypeVarValue}; | 13 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; |
14 | 14 | ||
15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
16 | /// Unify two types, but may coerce the first one to the second one | 16 | /// 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<T> Canonicalized<T> { | |||
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
170 | pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Substs { | 170 | pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option<Substs> { |
171 | let mut table = InferenceTable::new(); | 171 | let mut table = InferenceTable::new(); |
172 | let vars = Substs::builder(ty1.num_vars) | 172 | let vars = |
173 | .fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 173 | Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); |
174 | let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 174 | let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); |
175 | table.unify(&ty_with_vars, ty2); | 175 | if !table.unify(&ty_with_vars, ty2) { |
176 | Substs::builder(ty1.num_vars).fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))).build() | 176 | return None; |
177 | } | ||
178 | Some( | ||
179 | Substs::builder(ty1.num_vars) | ||
180 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | ||
181 | .build(), | ||
182 | ) | ||
177 | } | 183 | } |
178 | 184 | ||
179 | #[derive(Clone, Debug)] | 185 | #[derive(Clone, Debug)] |
@@ -183,9 +189,7 @@ pub(crate) struct InferenceTable { | |||
183 | 189 | ||
184 | impl InferenceTable { | 190 | impl InferenceTable { |
185 | pub fn new() -> Self { | 191 | pub fn new() -> Self { |
186 | InferenceTable { | 192 | InferenceTable { var_unification_table: InPlaceUnificationTable::new() } |
187 | var_unification_table: InPlaceUnificationTable::new(), | ||
188 | } | ||
189 | } | 193 | } |
190 | 194 | ||
191 | pub fn new_type_var(&mut self) -> Ty { | 195 | 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; | |||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::{ | 8 | use hir_def::{ |
9 | lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, | 9 | lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, |
10 | FunctionId, HasModule, ImplId, TraitId, | 10 | FunctionId, HasModule, ImplId, Lookup, TraitId, |
11 | }; | 11 | }; |
12 | use hir_expand::name::Name; | 12 | use hir_expand::name::Name; |
13 | use ra_db::CrateId; | 13 | use ra_db::CrateId; |
14 | use ra_prof::profile; | 14 | use ra_prof::profile; |
15 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
16 | 16 | ||
17 | use super::Substs; | ||
17 | use crate::{ | 18 | use crate::{ |
18 | autoderef, | 19 | autoderef, |
19 | db::HirDatabase, | 20 | db::HirDatabase, |
20 | primitive::{FloatBitness, Uncertain}, | 21 | primitive::{FloatBitness, Uncertain}, |
21 | utils::all_super_traits, | 22 | utils::all_super_traits, |
22 | Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, | 23 | Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
23 | }; | 24 | }; |
24 | 25 | ||
25 | /// This is used as a key for indexing impls. | 26 | /// This is used as a key for indexing impls. |
@@ -231,21 +232,42 @@ fn iterate_method_candidates_autoref<T>( | |||
231 | name: Option<&Name>, | 232 | name: Option<&Name>, |
232 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 233 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, |
233 | ) -> Option<T> { | 234 | ) -> Option<T> { |
234 | if let Some(result) = iterate_method_candidates_by_receiver(&deref_chain[0], &deref_chain[1..], db, resolver, name, &mut callback) { | 235 | if let Some(result) = iterate_method_candidates_by_receiver( |
236 | &deref_chain[0], | ||
237 | &deref_chain[1..], | ||
238 | db, | ||
239 | resolver, | ||
240 | name, | ||
241 | &mut callback, | ||
242 | ) { | ||
235 | return Some(result); | 243 | return Some(result); |
236 | } | 244 | } |
237 | let refed = Canonical { | 245 | let refed = Canonical { |
238 | num_vars: deref_chain[0].num_vars, | 246 | num_vars: deref_chain[0].num_vars, |
239 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | 247 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), |
240 | }; | 248 | }; |
241 | if let Some(result) = iterate_method_candidates_by_receiver(&refed, deref_chain, db, resolver, name, &mut callback) { | 249 | if let Some(result) = iterate_method_candidates_by_receiver( |
250 | &refed, | ||
251 | deref_chain, | ||
252 | db, | ||
253 | resolver, | ||
254 | name, | ||
255 | &mut callback, | ||
256 | ) { | ||
242 | return Some(result); | 257 | return Some(result); |
243 | } | 258 | } |
244 | let ref_muted = Canonical { | 259 | let ref_muted = Canonical { |
245 | num_vars: deref_chain[0].num_vars, | 260 | num_vars: deref_chain[0].num_vars, |
246 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | 261 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), |
247 | }; | 262 | }; |
248 | if let Some(result) = iterate_method_candidates_by_receiver(&ref_muted, deref_chain, db, resolver, name, &mut callback) { | 263 | if let Some(result) = iterate_method_candidates_by_receiver( |
264 | &ref_muted, | ||
265 | deref_chain, | ||
266 | db, | ||
267 | resolver, | ||
268 | name, | ||
269 | &mut callback, | ||
270 | ) { | ||
249 | return Some(result); | 271 | return Some(result); |
250 | } | 272 | } |
251 | None | 273 | None |
@@ -264,7 +286,14 @@ fn iterate_method_candidates_by_receiver<T>( | |||
264 | // be found in any of the derefs of receiver_ty, so we have to go through | 286 | // be found in any of the derefs of receiver_ty, so we have to go through |
265 | // that. | 287 | // that. |
266 | for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { | 288 | for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { |
267 | if let Some(result) = iterate_method_candidates_inner(self_ty, db, resolver, name, Some(receiver_ty), &mut callback) { | 289 | if let Some(result) = iterate_method_candidates_inner( |
290 | self_ty, | ||
291 | db, | ||
292 | resolver, | ||
293 | name, | ||
294 | Some(receiver_ty), | ||
295 | &mut callback, | ||
296 | ) { | ||
268 | return Some(result); | 297 | return Some(result); |
269 | } | 298 | } |
270 | } | 299 | } |
@@ -280,7 +309,9 @@ fn iterate_method_candidates_inner<T>( | |||
280 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 309 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, |
281 | ) -> Option<T> { | 310 | ) -> Option<T> { |
282 | let krate = resolver.krate()?; | 311 | let krate = resolver.krate()?; |
283 | if let Some(result) = iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) { | 312 | if let Some(result) = |
313 | iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) | ||
314 | { | ||
284 | return Some(result); | 315 | return Some(result); |
285 | } | 316 | } |
286 | if let Some(result) = | 317 | if let Some(result) = |
@@ -381,7 +412,31 @@ fn is_valid_candidate( | |||
381 | if !data.has_self_param { | 412 | if !data.has_self_param { |
382 | return false; | 413 | return false; |
383 | } | 414 | } |
384 | // TODO compare receiver ty | 415 | let substs = match m.lookup(db).container { |
416 | hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) | ||
417 | .push(self_ty.value.clone()) | ||
418 | .fill_with_unknown() | ||
419 | .build(), | ||
420 | hir_def::ContainerId::ImplId(impl_id) => { | ||
421 | let vars = | ||
422 | Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); | ||
423 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | ||
424 | let self_ty_with_vars = | ||
425 | Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; | ||
426 | if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value) | ||
427 | { | ||
428 | substs | ||
429 | } else { | ||
430 | return false; | ||
431 | } | ||
432 | } | ||
433 | hir_def::ContainerId::ModuleId(_) => unreachable!(), | ||
434 | }; | ||
435 | let sig = db.callable_item_signature(m.into()); | ||
436 | let receiver = sig.params()[0].clone().subst(&substs); | ||
437 | if receiver != receiver_ty.value { | ||
438 | return false; | ||
439 | } | ||
385 | } | 440 | } |
386 | true | 441 | true |
387 | } | 442 | } |