Skip to content

universes refactor 3 #55305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 2, 2018
Prev Previous commit
kill old-style-lub warnings
  • Loading branch information
nikomatsakis committed Oct 31, 2018
commit c244fd79f22f7a78016f20fa252d93bae474f4bd
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