diff options
author | Florian Diebold <[email protected]> | 2020-04-17 18:41:37 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-04-17 18:42:36 +0100 |
commit | 6a7fc76b89dca4d1b4e3e50047183535aee98627 (patch) | |
tree | 54d7d20ef4dc585bf85d176173f6d59273699681 /crates/ra_hir_ty | |
parent | f11236e511ec8470276180fa728f4e00c17ee3fb (diff) |
Fix type equality for dyn Trait
Fixes a lot of false type mismatches.
(And as always when touching the unification code, I have to say I'm looking
forward to replacing it by Chalk's...)
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 24 |
3 files changed, 65 insertions, 5 deletions
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 959b1e212..89200255a 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -51,7 +51,7 @@ impl<'a> InferenceContext<'a> { | |||
51 | // Trivial cases, this should go after `never` check to | 51 | // Trivial cases, this should go after `never` check to |
52 | // avoid infer result type to be never | 52 | // avoid infer result type to be never |
53 | _ => { | 53 | _ => { |
54 | if self.table.unify_inner_trivial(&from_ty, &to_ty) { | 54 | if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) { |
55 | return true; | 55 | return true; |
56 | } | 56 | } |
57 | } | 57 | } |
@@ -175,7 +175,7 @@ impl<'a> InferenceContext<'a> { | |||
175 | return self.table.unify_substs(st1, st2, 0); | 175 | return self.table.unify_substs(st1, st2, 0); |
176 | } | 176 | } |
177 | _ => { | 177 | _ => { |
178 | if self.table.unify_inner_trivial(&derefed_ty, &to_ty) { | 178 | if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) { |
179 | return true; | 179 | return true; |
180 | } | 180 | } |
181 | } | 181 | } |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 5f6cea8d3..ab0bc8b70 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -8,7 +8,8 @@ use test_utils::tested_by; | |||
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
11 | BoundVar, Canonical, DebruijnIndex, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk, | 11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, |
12 | TypeCtor, TypeWalk, | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | impl<'a> InferenceContext<'a> { | 15 | impl<'a> InferenceContext<'a> { |
@@ -226,16 +227,26 @@ impl InferenceTable { | |||
226 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { | 227 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { |
227 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) | 228 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) |
228 | } | 229 | } |
229 | _ => self.unify_inner_trivial(&ty1, &ty2), | 230 | |
231 | _ => self.unify_inner_trivial(&ty1, &ty2, depth), | ||
230 | } | 232 | } |
231 | } | 233 | } |
232 | 234 | ||
233 | pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 235 | pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { |
234 | match (ty1, ty2) { | 236 | match (ty1, ty2) { |
235 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | 237 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, |
236 | 238 | ||
237 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, | 239 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, |
238 | 240 | ||
241 | (Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => { | ||
242 | for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) { | ||
243 | if !self.unify_preds(pred1, pred2, depth + 1) { | ||
244 | return false; | ||
245 | } | ||
246 | } | ||
247 | true | ||
248 | } | ||
249 | |||
239 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 250 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
240 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 251 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
241 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) | 252 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) |
@@ -268,6 +279,31 @@ impl InferenceTable { | |||
268 | } | 279 | } |
269 | } | 280 | } |
270 | 281 | ||
282 | fn unify_preds( | ||
283 | &mut self, | ||
284 | pred1: &GenericPredicate, | ||
285 | pred2: &GenericPredicate, | ||
286 | depth: usize, | ||
287 | ) -> bool { | ||
288 | match (pred1, pred2) { | ||
289 | (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2)) | ||
290 | if tr1.trait_ == tr2.trait_ => | ||
291 | { | ||
292 | self.unify_substs(&tr1.substs, &tr2.substs, depth + 1) | ||
293 | } | ||
294 | (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) | ||
295 | if proj1.projection_ty.associated_ty == proj2.projection_ty.associated_ty => | ||
296 | { | ||
297 | self.unify_substs( | ||
298 | &proj1.projection_ty.parameters, | ||
299 | &proj2.projection_ty.parameters, | ||
300 | depth + 1, | ||
301 | ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) | ||
302 | } | ||
303 | _ => false, | ||
304 | } | ||
305 | } | ||
306 | |||
271 | /// If `ty` is a type variable with known type, returns that type; | 307 | /// If `ty` is a type variable with known type, returns that type; |
272 | /// otherwise, return ty. | 308 | /// otherwise, return ty. |
273 | pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | 309 | pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index dc517fc4a..f6e3e07cd 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2378,3 +2378,27 @@ fn main() { | |||
2378 | ); | 2378 | ); |
2379 | assert_eq!(t, "Foo"); | 2379 | assert_eq!(t, "Foo"); |
2380 | } | 2380 | } |
2381 | |||
2382 | #[test] | ||
2383 | fn trait_object_no_coercion() { | ||
2384 | assert_snapshot!( | ||
2385 | infer_with_mismatches(r#" | ||
2386 | trait Foo {} | ||
2387 | |||
2388 | fn foo(x: &dyn Foo) {} | ||
2389 | |||
2390 | fn test(x: &dyn Foo) { | ||
2391 | foo(x); | ||
2392 | } | ||
2393 | "#, true), | ||
2394 | @r###" | ||
2395 | [22; 23) 'x': &dyn Foo | ||
2396 | [35; 37) '{}': () | ||
2397 | [47; 48) 'x': &dyn Foo | ||
2398 | [60; 75) '{ foo(x); }': () | ||
2399 | [66; 69) 'foo': fn foo(&dyn Foo) | ||
2400 | [66; 72) 'foo(x)': () | ||
2401 | [70; 71) 'x': &dyn Foo | ||
2402 | "### | ||
2403 | ); | ||
2404 | } | ||