Skip to content

Commit

Permalink
kill old-style-lub warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Oct 31, 2018
1 parent 740117f commit c244fd7
Show file tree
Hide file tree
Showing 7 changed files with 4 additions and 317 deletions.
24 changes: 2 additions & 22 deletions src/librustc/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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())
}
}

Expand Down
256 changes: 0 additions & 256 deletions src/librustc/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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>,
Expand Down
24 changes: 2 additions & 22 deletions src/librustc/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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())
}
}

Expand Down
11 changes: 0 additions & 11 deletions src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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() {
Expand Down
Loading

0 comments on commit c244fd7

Please sign in to comment.