Skip to content

Commit

Permalink
Merge #4021
Browse files Browse the repository at this point in the history
4021: Fix type equality for dyn Trait r=matklad a=flodiebold

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...)

Co-authored-by: Florian Diebold <[email protected]>
  • Loading branch information
bors[bot] and flodiebold authored Apr 17, 2020
2 parents f11236e + 6a7fc76 commit 8a4ceba
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
4 changes: 2 additions & 2 deletions crates/ra_hir_ty/src/infer/coerce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl<'a> InferenceContext<'a> {
// Trivial cases, this should go after `never` check to
// avoid infer result type to be never
_ => {
if self.table.unify_inner_trivial(&from_ty, &to_ty) {
if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) {
return true;
}
}
Expand Down Expand Up @@ -175,7 +175,7 @@ impl<'a> InferenceContext<'a> {
return self.table.unify_substs(st1, st2, 0);
}
_ => {
if self.table.unify_inner_trivial(&derefed_ty, &to_ty) {
if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) {
return true;
}
}
Expand Down
42 changes: 39 additions & 3 deletions crates/ra_hir_ty/src/infer/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use test_utils::tested_by;

use super::{InferenceContext, Obligation};
use crate::{
BoundVar, Canonical, DebruijnIndex, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk,
BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
TypeCtor, TypeWalk,
};

impl<'a> InferenceContext<'a> {
Expand Down Expand Up @@ -226,16 +227,26 @@ impl InferenceTable {
(Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
}
_ => self.unify_inner_trivial(&ty1, &ty2),

_ => self.unify_inner_trivial(&ty1, &ty2, depth),
}
}

pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
match (ty1, ty2) {
(Ty::Unknown, _) | (_, Ty::Unknown) => true,

(Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true,

(Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => {
for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) {
if !self.unify_preds(pred1, pred2, depth + 1) {
return false;
}
}
true
}

(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
Expand Down Expand Up @@ -268,6 +279,31 @@ impl InferenceTable {
}
}

fn unify_preds(
&mut self,
pred1: &GenericPredicate,
pred2: &GenericPredicate,
depth: usize,
) -> bool {
match (pred1, pred2) {
(GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2))
if tr1.trait_ == tr2.trait_ =>
{
self.unify_substs(&tr1.substs, &tr2.substs, depth + 1)
}
(GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2))
if proj1.projection_ty.associated_ty == proj2.projection_ty.associated_ty =>
{
self.unify_substs(
&proj1.projection_ty.parameters,
&proj2.projection_ty.parameters,
depth + 1,
) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1)
}
_ => false,
}
}

/// If `ty` is a type variable with known type, returns that type;
/// otherwise, return ty.
pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
Expand Down
24 changes: 24 additions & 0 deletions crates/ra_hir_ty/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2378,3 +2378,27 @@ fn main() {
);
assert_eq!(t, "Foo");
}

#[test]
fn trait_object_no_coercion() {
assert_snapshot!(
infer_with_mismatches(r#"
trait Foo {}
fn foo(x: &dyn Foo) {}
fn test(x: &dyn Foo) {
foo(x);
}
"#, true),
@r###"
[22; 23) 'x': &dyn Foo
[35; 37) '{}': ()
[47; 48) 'x': &dyn Foo
[60; 75) '{ foo(x); }': ()
[66; 69) 'foo': fn foo(&dyn Foo)
[66; 72) 'foo(x)': ()
[70; 71) 'x': &dyn Foo
"###
);
}

0 comments on commit 8a4ceba

Please sign in to comment.