Auto merge of #45853 - nikomatsakis:chalk-simplify-hr-lub-glb, r=arielb1
Simplify higher-ranked LUB/GLB This is a better version of https://github.com/rust-lang/rust/pull/44211. It still makes higher-ranked LUB/GLB into a hard equality test, however, it does try to identify that something changed and issue a notice to the user. I wroteup https://github.com/rust-lang/rust/issues/45852 as a tracking issue for this change. Currently, this moves straight to a hard-error, on the basis that the crater run in #44211 saw no impact. It might be good to retest -- or perhaps to try for a warning period. Trying to do the latter in a precise way would be somewhat painful, but an imprecise way might suffice -- that is, we could issue warning *whenever* a LUB/GLB operation succeeds that will later fail, even if it doesn't ultimately impact the type check. I could experiment with this. ~~I am *mildly* wary about landing this independently of other code that moves to a universe-based system. In particular, I was nervous that this change would make coherence accepts new pairs of impls that will later be errors. I have the code for the universe-based approach available, I hope to open an PR and run some tests on its impact very shortly.~~ @arielb1 points out that I was being silly. r? @arielb1
This commit is contained in:
commit
18d8acf41d
@ -762,9 +762,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
self.note_error_origin(diag, &cause);
|
||||
self.check_and_note_conflicting_crates(diag, terr, span);
|
||||
self.tcx.note_and_explain_type_err(diag, terr, span);
|
||||
|
||||
// It reads better to have the error origin as the final
|
||||
// thing.
|
||||
self.note_error_origin(diag, &cause);
|
||||
}
|
||||
|
||||
pub fn report_and_explain_type_error(&self,
|
||||
@ -772,6 +775,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
terr: &TypeError<'tcx>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
debug!("report_and_explain_type_error(trace={:?}, terr={:?})",
|
||||
trace,
|
||||
terr);
|
||||
|
||||
let span = trace.cause.span;
|
||||
let failure_str = trace.cause.as_failure_str();
|
||||
let mut diag = match trace.cause.code {
|
||||
|
@ -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,32 @@ 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)
|
||||
debug!("binders(a={:?}, b={:?})", a, b);
|
||||
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()
|
||||
});
|
||||
debug!("binders: was_error={:?}", was_error);
|
||||
|
||||
// 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) => {
|
||||
debug!("binders: error occurred, was_error={:?}", was_error);
|
||||
if !was_error {
|
||||
Err(TypeError::OldStyleLUB(Box::new(err)))
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use super::{CombinedSnapshot,
|
||||
use super::combine::CombineFields;
|
||||
use super::region_constraints::{TaintDirections};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
@ -246,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
snapshot: &CombinedSnapshot,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
r0: ty::Region<'tcx>)
|
||||
-> ty::Region<'tcx> {
|
||||
// Regions that pre-dated the LUB computation stay as they are.
|
||||
@ -342,7 +343,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
snapshot: &CombinedSnapshot,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
a_vars: &[ty::RegionVid],
|
||||
b_vars: &[ty::RegionVid],
|
||||
r0: ty::Region<'tcx>)
|
||||
@ -411,7 +412,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
r: ty::Region<'tcx>) -> ty::Region<'tcx>
|
||||
{
|
||||
for (a_br, a_r) in a_map {
|
||||
@ -434,7 +435,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
|
||||
map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
-> Vec<ty::RegionVid> {
|
||||
map.iter()
|
||||
.map(|(_, &r)| match *r {
|
||||
|
@ -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,32 @@ 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)
|
||||
debug!("binders(a={:?}, b={:?})", a, b);
|
||||
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()
|
||||
});
|
||||
debug!("binders: was_error={:?}", was_error);
|
||||
|
||||
// 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) => {
|
||||
debug!("binders: error occurred, was_error={:?}", was_error);
|
||||
if !was_error {
|
||||
Err(TypeError::OldStyleLUB(Box::new(err)))
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ use ty::relate::RelateResult;
|
||||
use traits::{self, ObligationCause, PredicateObligations, Reveal};
|
||||
use rustc_data_structures::unify::{self, UnificationTable};
|
||||
use std::cell::{Cell, RefCell, Ref, RefMut};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
@ -184,7 +185,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
|
||||
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
|
||||
/// region that each late-bound region was replaced with.
|
||||
pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, ty::Region<'tcx>>;
|
||||
pub type SkolemizationMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
|
||||
|
||||
/// See `error_reporting` module for more details
|
||||
#[derive(Clone, Debug)]
|
||||
@ -1384,7 +1385,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
span: Span,
|
||||
lbrct: LateBoundRegionConversionTime,
|
||||
value: &ty::Binder<T>)
|
||||
-> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
-> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
self.tcx.replace_late_bound_regions(
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,6 +298,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
db.span_note(found.origin_span,
|
||||
"...that also applies to the same type variable here");
|
||||
}
|
||||
OldStyleLUB(err) => {
|
||||
db.note("this was previously accepted by the compiler but has been phased out");
|
||||
db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");
|
||||
|
||||
self.note_and_explain_type_err(db, &err, sp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ use middle::const_val::ConstVal;
|
||||
use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||
|
||||
use std::fmt;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use std::collections::BTreeMap;
|
||||
use util::nodemap::FxHashSet;
|
||||
|
||||
/// The TypeFoldable trait is implemented for every type that can be folded.
|
||||
/// Basically, every type that has a corresponding method in TypeFolder.
|
||||
@ -324,14 +325,14 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
current_depth: u32,
|
||||
fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
||||
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>
|
||||
map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn replace_late_bound_regions<T,F>(self,
|
||||
value: &Binder<T>,
|
||||
mut f: F)
|
||||
-> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
-> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||
T : TypeFoldable<'tcx>,
|
||||
{
|
||||
@ -438,7 +439,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
|
||||
tcx,
|
||||
current_depth: 1,
|
||||
fld_r,
|
||||
map: FxHashMap()
|
||||
map: BTreeMap::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 |
|
||||
|
@ -353,28 +353,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn t_rptr_static(&self) -> Ty<'tcx> {
|
||||
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static,
|
||||
self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn t_rptr_empty(&self) -> Ty<'tcx> {
|
||||
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty,
|
||||
self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
|
||||
self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
|
||||
}
|
||||
|
||||
pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
||||
self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2)
|
||||
}
|
||||
|
||||
pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
|
||||
self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2)
|
||||
}
|
||||
|
||||
/// Checks that `t1 <: t2` is true (this may register additional
|
||||
/// region checks).
|
||||
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||
@ -399,37 +381,6 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `LUB(t1,t2) == t_lub`
|
||||
pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
|
||||
match self.lub(t1, t2) {
|
||||
Ok(InferOk { obligations, value: t }) => {
|
||||
// None of these tests should require nested obligations:
|
||||
assert!(obligations.is_empty());
|
||||
|
||||
self.assert_eq(t, t_lub);
|
||||
}
|
||||
Err(ref e) => panic!("unexpected error in LUB: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `GLB(t1,t2) == t_glb`
|
||||
pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
|
||||
debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb);
|
||||
match self.glb(t1, t2) {
|
||||
Err(e) => panic!("unexpected error computing LUB: {:?}", e),
|
||||
Ok(InferOk { obligations, value: t }) => {
|
||||
// None of these tests should require nested obligations:
|
||||
assert!(obligations.is_empty());
|
||||
|
||||
self.assert_eq(t, t_glb);
|
||||
|
||||
// sanity check for good measure:
|
||||
self.assert_subtype(t, t1);
|
||||
self.assert_subtype(t, t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -508,169 +459,6 @@ fn sub_free_bound_false_infer() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_free_bound_infer() {
|
||||
//! Test result of:
|
||||
//!
|
||||
//! LUB(fn(_#1), for<'b> fn(&'b isize))
|
||||
//!
|
||||
//! This should yield `fn(&'_ isize)`. We check
|
||||
//! that it yields `fn(&'x isize)` for some free `'x`,
|
||||
//! anyhow.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_bound_bound() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_bound2 = env.t_rptr_late_bound(2);
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_bound_free() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_bound_static() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_bound_bound_inverse_order() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_bound2 = env.t_rptr_late_bound(2);
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
|
||||
env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
|
||||
env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_free_free() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
let t_rptr_free2 = env.t_rptr_free(2);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_returning_scope() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_scope10 = env.t_rptr_scope(10);
|
||||
let t_rptr_scope11 = env.t_rptr_scope(11);
|
||||
let t_rptr_empty = env.t_rptr_empty();
|
||||
env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_scope11], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_empty], env.tcx().types.isize));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_free_free_with_common_scope() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
let t_rptr_free2 = env.t_rptr_free(2);
|
||||
let t_rptr_scope = env.t_rptr_scope(1);
|
||||
env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_scope], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_bound() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_bound2 = env.t_rptr_late_bound(2);
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_free() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_free_infer() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
|
||||
// compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
|
||||
// which should yield for<'b> fn(&'b isize) -> isize
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
|
||||
// as a side-effect, computing GLB should unify `_` with
|
||||
// `&'_ isize`
|
||||
let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
|
||||
match t_resolve1.sty {
|
||||
ty::TyRef(..) => {}
|
||||
_ => {
|
||||
panic!("t_resolve1={:?}", t_resolve1);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_static() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
})
|
||||
}
|
||||
|
||||
/// Test substituting a bound region into a function, which introduces another level of binding.
|
||||
/// This requires adjusting the Debruijn index.
|
||||
#[test]
|
||||
|
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);
|
||||
}
|
36
src/test/ui/lub-glb/old-lub-glb-hr.rs
Normal file
36
src/test/ui/lub-glb/old-lub-glb-hr.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2017 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 that we give a note when the old LUB/GLB algorithm would have
|
||||
// succeeded but the new code (which is stricter) gives an error.
|
||||
|
||||
fn foo(
|
||||
x: fn(&u8, &u8),
|
||||
y: for<'a> fn(&'a u8, &'a u8),
|
||||
) {
|
||||
let z = match 22 {
|
||||
0 => x,
|
||||
_ => y,
|
||||
};
|
||||
}
|
||||
|
||||
fn bar(
|
||||
x: fn(&u8, &u8),
|
||||
y: for<'a> fn(&'a u8, &'a u8),
|
||||
) {
|
||||
let z = match 22 {
|
||||
// No error with an explicit cast:
|
||||
0 => x as for<'a> fn(&'a u8, &'a u8),
|
||||
_ => y,
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
22
src/test/ui/lub-glb/old-lub-glb-hr.stderr
Normal file
22
src/test/ui/lub-glb/old-lub-glb-hr.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/old-lub-glb-hr.rs:18:13
|
||||
|
|
||||
18 | let z = match 22 {
|
||||
| _____________^
|
||||
19 | | 0 => x,
|
||||
20 | | _ => y,
|
||||
21 | | };
|
||||
| |_____^ expected bound lifetime parameter, found concrete lifetime
|
||||
|
|
||||
= note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
|
||||
found type `for<'a> fn(&'a u8, &'a u8)`
|
||||
= note: this was previously accepted by the compiler but has been phased out
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/45852
|
||||
note: match arm with an incompatible type
|
||||
--> $DIR/old-lub-glb-hr.rs:20:14
|
||||
|
|
||||
20 | _ => y,
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
38
src/test/ui/lub-glb/old-lub-glb-object.rs
Normal file
38
src/test/ui/lub-glb/old-lub-glb-object.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2017 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 that we give a note when the old LUB/GLB algorithm would have
|
||||
// succeeded but the new code (which is stricter) gives an error.
|
||||
|
||||
trait Foo<T, U> { }
|
||||
|
||||
fn foo(
|
||||
x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
|
||||
y: &for<'a> Foo<&'a u8, &'a u8>,
|
||||
) {
|
||||
let z = match 22 {
|
||||
0 => x,
|
||||
_ => y,
|
||||
};
|
||||
}
|
||||
|
||||
fn bar(
|
||||
x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
|
||||
y: &for<'a> Foo<&'a u8, &'a u8>,
|
||||
) {
|
||||
// Accepted with explicit case:
|
||||
let z = match 22 {
|
||||
0 => x as &for<'a> Foo<&'a u8, &'a u8>,
|
||||
_ => y,
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
22
src/test/ui/lub-glb/old-lub-glb-object.stderr
Normal file
22
src/test/ui/lub-glb/old-lub-glb-object.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error[E0308]: match arms have incompatible types
|
||||
--> $DIR/old-lub-glb-object.rs:20:13
|
||||
|
|
||||
20 | let z = match 22 {
|
||||
| _____________^
|
||||
21 | | 0 => x,
|
||||
22 | | _ => y,
|
||||
23 | | };
|
||||
| |_____^ expected bound lifetime parameter 'a, found concrete lifetime
|
||||
|
|
||||
= note: expected type `&for<'a, 'b> Foo<&'a u8, &'b u8>`
|
||||
found type `&for<'a> Foo<&'a u8, &'a u8>`
|
||||
= note: this was previously accepted by the compiler but has been phased out
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/45852
|
||||
note: match arm with an incompatible type
|
||||
--> $DIR/old-lub-glb-object.rs:22:14
|
||||
|
|
||||
22 | _ => y,
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user