make LUB/GLB of higher-ranked things actually do EQ
This commit is contained in:
parent
02eed2e9a5
commit
397973b601
@ -15,6 +15,7 @@ use super::Subtype;
|
|||||||
|
|
||||||
use traits::ObligationCause;
|
use traits::ObligationCause;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, Ty, TyCtxt};
|
||||||
|
use ty::error::TypeError;
|
||||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||||
|
|
||||||
/// "Greatest lower bound" (common subtype)
|
/// "Greatest lower bound" (common subtype)
|
||||||
@ -74,7 +75,29 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
|||||||
-> RelateResult<'tcx, ty::Binder<T>>
|
-> RelateResult<'tcx, ty::Binder<T>>
|
||||||
where T: Relate<'tcx>
|
where T: Relate<'tcx>
|
||||||
{
|
{
|
||||||
self.fields.higher_ranked_glb(a, b, self.a_is_expected)
|
let was_error = self.infcx().probe(|_snapshot| {
|
||||||
|
// Subtle: use a fresh combine-fields here because we recover
|
||||||
|
// from Err. Doing otherwise could propagate obligations out
|
||||||
|
// through our `self.obligations` field.
|
||||||
|
self.infcx()
|
||||||
|
.combine_fields(self.fields.trace.clone(), self.fields.param_env)
|
||||||
|
.higher_ranked_glb(a, b, self.a_is_expected)
|
||||||
|
.is_err()
|
||||||
|
});
|
||||||
|
|
||||||
|
// When higher-ranked types are involved, computing the LUB is
|
||||||
|
// very challenging, switch to invariance. This is obviously
|
||||||
|
// overly conservative but works ok in practice.
|
||||||
|
match self.relate_with_variance(ty::Variance::Invariant, a, b) {
|
||||||
|
Ok(_) => Ok(a.clone()),
|
||||||
|
Err(err) => {
|
||||||
|
if !was_error {
|
||||||
|
Err(TypeError::OldStyleLUB(Box::new(err)))
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ use super::Subtype;
|
|||||||
|
|
||||||
use traits::ObligationCause;
|
use traits::ObligationCause;
|
||||||
use ty::{self, Ty, TyCtxt};
|
use ty::{self, Ty, TyCtxt};
|
||||||
|
use ty::error::TypeError;
|
||||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||||
|
|
||||||
/// "Least upper bound" (common supertype)
|
/// "Least upper bound" (common supertype)
|
||||||
@ -74,7 +75,29 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
|||||||
-> RelateResult<'tcx, ty::Binder<T>>
|
-> RelateResult<'tcx, ty::Binder<T>>
|
||||||
where T: Relate<'tcx>
|
where T: Relate<'tcx>
|
||||||
{
|
{
|
||||||
self.fields.higher_ranked_lub(a, b, self.a_is_expected)
|
let was_error = self.infcx().probe(|_snapshot| {
|
||||||
|
// Subtle: use a fresh combine-fields here because we recover
|
||||||
|
// from Err. Doing otherwise could propagate obligations out
|
||||||
|
// through our `self.obligations` field.
|
||||||
|
self.infcx()
|
||||||
|
.combine_fields(self.fields.trace.clone(), self.fields.param_env)
|
||||||
|
.higher_ranked_lub(a, b, self.a_is_expected)
|
||||||
|
.is_err()
|
||||||
|
});
|
||||||
|
|
||||||
|
// When higher-ranked types are involved, computing the LUB is
|
||||||
|
// very challenging, switch to invariance. This is obviously
|
||||||
|
// overly conservative but works ok in practice.
|
||||||
|
match self.relate_with_variance(ty::Variance::Invariant, a, b) {
|
||||||
|
Ok(_) => Ok(a.clone()),
|
||||||
|
Err(err) => {
|
||||||
|
if !was_error {
|
||||||
|
Err(TypeError::OldStyleLUB(Box::new(err)))
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ pub enum TypeError<'tcx> {
|
|||||||
ProjectionBoundsLength(ExpectedFound<usize>),
|
ProjectionBoundsLength(ExpectedFound<usize>),
|
||||||
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
|
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
|
||||||
ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
|
ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
|
||||||
|
|
||||||
|
OldStyleLUB(Box<TypeError<'tcx>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
|
||||||
@ -170,6 +172,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||||||
report_maybe_different(f, format!("trait `{}`", values.expected),
|
report_maybe_different(f, format!("trait `{}`", values.expected),
|
||||||
format!("trait `{}`", values.found))
|
format!("trait `{}`", values.found))
|
||||||
}
|
}
|
||||||
|
OldStyleLUB(ref err) => {
|
||||||
|
write!(f, "{}", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,7 +428,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
|||||||
TyParamDefaultMismatch(ref x) => {
|
TyParamDefaultMismatch(ref x) => {
|
||||||
return tcx.lift(x).map(TyParamDefaultMismatch)
|
return tcx.lift(x).map(TyParamDefaultMismatch)
|
||||||
}
|
}
|
||||||
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
|
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
|
||||||
|
OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1174,6 +1175,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
|
|||||||
Sorts(x) => Sorts(x.fold_with(folder)),
|
Sorts(x) => Sorts(x.fold_with(folder)),
|
||||||
TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
|
TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
|
||||||
ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
|
ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
|
||||||
|
OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1191,6 +1193,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
|
|||||||
b.visit_with(visitor)
|
b.visit_with(visitor)
|
||||||
},
|
},
|
||||||
Sorts(x) => x.visit_with(visitor),
|
Sorts(x) => x.visit_with(visitor),
|
||||||
|
OldStyleLUB(ref x) => x.visit_with(visitor),
|
||||||
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
|
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
|
||||||
ExistentialMismatch(x) => x.visit_with(visitor),
|
ExistentialMismatch(x) => x.visit_with(visitor),
|
||||||
Mismatch |
|
Mismatch |
|
||||||
|
24
src/test/run-pass/lub-glb-with-unbound-infer-var.rs
Normal file
24
src/test/run-pass/lub-glb-with-unbound-infer-var.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test for a specific corner case: when we compute the LUB of two fn
|
||||||
|
// types and their parameters have unbound variables. In that case, we
|
||||||
|
// wind up relating those two variables. This was causing an ICE in an
|
||||||
|
// in-progress PR.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a_f: fn(_) = |_| ();
|
||||||
|
let b_f: fn(_) = |_| ();
|
||||||
|
let c_f = match 22 {
|
||||||
|
0 => a_f,
|
||||||
|
_ => b_f,
|
||||||
|
};
|
||||||
|
c_f(4);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user