mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-30 15:03:42 +00:00
Merge #4021
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 <florian.diebold@freiheit.com>
This commit is contained in:
commit
8a4cebafca
3 changed files with 65 additions and 5 deletions
|
@ -51,7 +51,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
// Trivial cases, this should go after `never` check to
|
// Trivial cases, this should go after `never` check to
|
||||||
// avoid infer result type to be never
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
return self.table.unify_substs(st1, st2, 0);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ use test_utils::tested_by;
|
||||||
|
|
||||||
use super::{InferenceContext, Obligation};
|
use super::{InferenceContext, Obligation};
|
||||||
use crate::{
|
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> {
|
impl<'a> InferenceContext<'a> {
|
||||||
|
@ -226,16 +227,26 @@ impl InferenceTable {
|
||||||
(Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
|
(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_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) {
|
match (ty1, ty2) {
|
||||||
(Ty::Unknown, _) | (_, Ty::Unknown) => true,
|
(Ty::Unknown, _) | (_, Ty::Unknown) => true,
|
||||||
|
|
||||||
(Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => 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::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
||||||
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
||||||
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
|
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
|
||||||
|
@ -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;
|
/// If `ty` is a type variable with known type, returns that type;
|
||||||
/// otherwise, return ty.
|
/// otherwise, return ty.
|
||||||
pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
|
pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
|
||||||
|
|
|
@ -2378,3 +2378,27 @@ fn main() {
|
||||||
);
|
);
|
||||||
assert_eq!(t, "Foo");
|
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
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue