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 ty::{self, Ty, TyCtxt};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
|
||||
/// "Greatest lower bound" (common subtype)
|
||||
@ -74,7 +75,29 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
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 ty::{self, Ty, TyCtxt};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
|
||||
/// "Least upper bound" (common supertype)
|
||||
@ -74,7 +75,29 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
-> RelateResult<'tcx, ty::Binder<T>>
|
||||
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>),
|
||||
TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
|
||||
ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
|
||||
|
||||
OldStyleLUB(Box<TypeError<'tcx>>),
|
||||
}
|
||||
|
||||
#[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),
|
||||
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) => {
|
||||
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)),
|
||||
TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(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)
|
||||
},
|
||||
Sorts(x) => x.visit_with(visitor),
|
||||
OldStyleLUB(ref x) => x.visit_with(visitor),
|
||||
TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
|
||||
ExistentialMismatch(x) => x.visit_with(visitor),
|
||||
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