mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 11:48:30 +00:00
kill old-style-lub warnings
This commit is contained in:
parent
740117f905
commit
c244fd79f2
@ -15,7 +15,6 @@ 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)
|
||||
@ -76,31 +75,12 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
|
||||
Ok(a.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ use super::region_constraints::{TaintDirections};
|
||||
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use std::collections::BTreeMap;
|
||||
use syntax_pos::Span;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
@ -202,261 +201,6 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
Ok(HrMatchResult { value: a_value })
|
||||
});
|
||||
}
|
||||
|
||||
pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let span = self.trace.cause.span;
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, a);
|
||||
let (b_with_fresh, _) =
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, b);
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
|
||||
let result0 =
|
||||
self.infcx.resolve_type_vars_if_possible(&result0);
|
||||
debug!("lub result0 = {:?}", result0);
|
||||
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace.cause.span;
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
|
||||
&new_vars, &a_map, r));
|
||||
|
||||
debug!("lub({:?},{:?}) = {:?}",
|
||||
a,
|
||||
b,
|
||||
result1);
|
||||
|
||||
Ok(ty::Binder::bind(result1))
|
||||
});
|
||||
|
||||
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
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.
|
||||
if !is_var_in_set(new_vars, r0) {
|
||||
assert!(!r0.is_late_bound());
|
||||
debug!("generalize_region(r0={:?}): not new variable", r0);
|
||||
return r0;
|
||||
}
|
||||
|
||||
let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
|
||||
|
||||
// Variables created during LUB computation which are
|
||||
// *related* to regions that pre-date the LUB computation
|
||||
// stay as they are.
|
||||
if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
|
||||
debug!("generalize_region(r0={:?}): \
|
||||
non-new-variables found in {:?}",
|
||||
r0, tainted);
|
||||
assert!(!r0.is_late_bound());
|
||||
return r0;
|
||||
}
|
||||
|
||||
// Otherwise, the variable must be associated with at
|
||||
// least one of the variables representing bound regions
|
||||
// in both A and B. Replace the variable with the "first"
|
||||
// bound region from A that we find it to be associated
|
||||
// with.
|
||||
for (a_br, a_r) in a_map {
|
||||
if tainted.iter().any(|x| x == a_r) {
|
||||
debug!("generalize_region(r0={:?}): \
|
||||
replacing with {:?}, tainted={:?}",
|
||||
r0, *a_br, tainted);
|
||||
return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
|
||||
}
|
||||
}
|
||||
|
||||
span_bug!(
|
||||
span,
|
||||
"region {:?} is not associated with any bound region from A!",
|
||||
r0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
debug!("higher_ranked_glb({:?}, {:?})",
|
||||
a, b);
|
||||
|
||||
// Make a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.trace.cause.span, HigherRankedType, a);
|
||||
let (b_with_fresh, b_map) =
|
||||
self.infcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.trace.cause.span, HigherRankedType, b);
|
||||
let a_vars = var_ids(self, &a_map);
|
||||
let b_vars = var_ids(self, &b_map);
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
|
||||
let result0 =
|
||||
self.infcx.resolve_type_vars_if_possible(&result0);
|
||||
debug!("glb result0 = {:?}", result0);
|
||||
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace.cause.span;
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
|
||||
&new_vars,
|
||||
&a_map, &a_vars, &b_vars,
|
||||
r));
|
||||
|
||||
debug!("glb({:?},{:?}) = {:?}",
|
||||
a,
|
||||
b,
|
||||
result1);
|
||||
|
||||
Ok(ty::Binder::bind(result1))
|
||||
});
|
||||
|
||||
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
a_vars: &[ty::RegionVid],
|
||||
b_vars: &[ty::RegionVid],
|
||||
r0: ty::Region<'tcx>)
|
||||
-> ty::Region<'tcx> {
|
||||
if !is_var_in_set(new_vars, r0) {
|
||||
assert!(!r0.is_late_bound());
|
||||
return r0;
|
||||
}
|
||||
|
||||
let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
|
||||
|
||||
let mut a_r = None;
|
||||
let mut b_r = None;
|
||||
let mut only_new_vars = true;
|
||||
for r in &tainted {
|
||||
if is_var_in_set(a_vars, *r) {
|
||||
if a_r.is_some() {
|
||||
return fresh_bound_variable(infcx, debruijn);
|
||||
} else {
|
||||
a_r = Some(*r);
|
||||
}
|
||||
} else if is_var_in_set(b_vars, *r) {
|
||||
if b_r.is_some() {
|
||||
return fresh_bound_variable(infcx, debruijn);
|
||||
} else {
|
||||
b_r = Some(*r);
|
||||
}
|
||||
} else if !is_var_in_set(new_vars, *r) {
|
||||
only_new_vars = false;
|
||||
}
|
||||
}
|
||||
|
||||
// NB---I do not believe this algorithm computes
|
||||
// (necessarily) the GLB. As written it can
|
||||
// spuriously fail. In particular, if there is a case
|
||||
// like: |fn(&a)| and fn(fn(&b)), where a and b are
|
||||
// free, it will return fn(&c) where c = GLB(a,b). If
|
||||
// however this GLB is not defined, then the result is
|
||||
// an error, even though something like
|
||||
// "fn<X>(fn(&X))" where X is bound would be a
|
||||
// subtype of both of those.
|
||||
//
|
||||
// The problem is that if we were to return a bound
|
||||
// variable, we'd be computing a lower-bound, but not
|
||||
// necessarily the *greatest* lower-bound.
|
||||
//
|
||||
// Unfortunately, this problem is non-trivial to solve,
|
||||
// because we do not know at the time of computing the GLB
|
||||
// whether a GLB(a,b) exists or not, because we haven't
|
||||
// run region inference (or indeed, even fully computed
|
||||
// the region hierarchy!). The current algorithm seems to
|
||||
// works ok in practice.
|
||||
|
||||
if a_r.is_some() && b_r.is_some() && only_new_vars {
|
||||
// Related to exactly one bound variable from each fn:
|
||||
return rev_lookup(infcx, span, a_map, a_r.unwrap());
|
||||
} else if a_r.is_none() && b_r.is_none() {
|
||||
// Not related to bound variables from either fn:
|
||||
assert!(!r0.is_late_bound());
|
||||
return r0;
|
||||
} else {
|
||||
// Other:
|
||||
return fresh_bound_variable(infcx, debruijn);
|
||||
}
|
||||
}
|
||||
|
||||
fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
r: ty::Region<'tcx>) -> ty::Region<'tcx>
|
||||
{
|
||||
for (a_br, a_r) in a_map {
|
||||
if *a_r == r {
|
||||
return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br));
|
||||
}
|
||||
}
|
||||
span_bug!(
|
||||
span,
|
||||
"could not find original bound region for {:?}",
|
||||
r);
|
||||
}
|
||||
|
||||
fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
debruijn: ty::DebruijnIndex)
|
||||
-> ty::Region<'tcx> {
|
||||
infcx.borrow_region_constraints().new_bound(infcx.tcx, debruijn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
|
||||
map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
-> Vec<ty::RegionVid> {
|
||||
map.iter()
|
||||
.map(|(_, &r)| match *r {
|
||||
ty::ReVar(r) => { r }
|
||||
_ => {
|
||||
span_bug!(
|
||||
fields.trace.cause.span,
|
||||
"found non-region-vid: {:?}",
|
||||
r);
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
@ -15,7 +15,6 @@ 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)
|
||||
@ -76,31 +75,12 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
|
||||
where T: Relate<'tcx>
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
|
||||
Ok(a.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,6 @@ pub enum TypeError<'tcx> {
|
||||
ProjectionMismatched(ExpectedFound<DefId>),
|
||||
ProjectionBoundsLength(ExpectedFound<usize>),
|
||||
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
|
||||
|
||||
OldStyleLUB(Box<TypeError<'tcx>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
@ -166,9 +164,6 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,12 +261,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
CyclicTy(ty) => {
|
||||
// Watch out for various cases of cyclic types and try to explain.
|
||||
if ty.is_closure() || ty.is_generator() {
|
||||
|
@ -455,7 +455,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||
ProjectionMismatched(x) => ProjectionMismatched(x),
|
||||
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
|
||||
Sorts(ref x) => return tcx.lift(x).map(Sorts),
|
||||
OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
|
||||
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
|
||||
})
|
||||
}
|
||||
@ -1000,7 +999,6 @@ EnumTypeFoldableImpl! {
|
||||
(ty::error::TypeError::ProjectionBoundsLength)(x),
|
||||
(ty::error::TypeError::Sorts)(x),
|
||||
(ty::error::TypeError::ExistentialMismatch)(x),
|
||||
(ty::error::TypeError::OldStyleLUB)(x),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,6 @@ LL | | };
|
||||
|
|
||||
= 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
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -11,8 +11,6 @@ LL | | };
|
||||
|
|
||||
= note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
|
||||
found type `&dyn 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
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user