Skip to content

Commit 083c433

Browse files
committed
Revert "make LUB/GLB of higher-ranked things actually do EQ"
This reverts commit 7226cda.
1 parent 75012f4 commit 083c433

File tree

3 files changed

+259
-10
lines changed

3 files changed

+259
-10
lines changed

src/librustc/infer/glb.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
7474
-> RelateResult<'tcx, ty::Binder<T>>
7575
where T: Relate<'tcx>
7676
{
77-
// Otherwise, we make the (overly strict) requirement that
78-
// the two sides are equal.
79-
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
80-
Ok(a.clone())
77+
self.fields.higher_ranked_glb(a, b, self.a_is_expected)
8178
}
8279
}
8380

src/librustc/infer/higher_ranked/mod.rs

+255
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,261 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
195195
Ok(HrMatchResult { value: a_value })
196196
});
197197
}
198+
199+
pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
200+
-> RelateResult<'tcx, Binder<T>>
201+
where T: Relate<'tcx>
202+
{
203+
// Start a snapshot so we can examine "all bindings that were
204+
// created as part of this type comparison".
205+
return self.infcx.commit_if_ok(|snapshot| {
206+
// Instantiate each bound region with a fresh region variable.
207+
let span = self.trace.cause.span;
208+
let (a_with_fresh, a_map) =
209+
self.infcx.replace_late_bound_regions_with_fresh_var(
210+
span, HigherRankedType, a);
211+
let (b_with_fresh, _) =
212+
self.infcx.replace_late_bound_regions_with_fresh_var(
213+
span, HigherRankedType, b);
214+
215+
// Collect constraints.
216+
let result0 =
217+
self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
218+
let result0 =
219+
self.infcx.resolve_type_vars_if_possible(&result0);
220+
debug!("lub result0 = {:?}", result0);
221+
222+
// Generalize the regions appearing in result0 if possible
223+
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
224+
let span = self.trace.cause.span;
225+
let result1 =
226+
fold_regions_in(
227+
self.tcx(),
228+
&result0,
229+
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
230+
&new_vars, &a_map, r));
231+
232+
debug!("lub({:?},{:?}) = {:?}",
233+
a,
234+
b,
235+
result1);
236+
237+
Ok(ty::Binder(result1))
238+
});
239+
240+
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
241+
span: Span,
242+
snapshot: &CombinedSnapshot,
243+
debruijn: ty::DebruijnIndex,
244+
new_vars: &[ty::RegionVid],
245+
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
246+
r0: ty::Region<'tcx>)
247+
-> ty::Region<'tcx> {
248+
// Regions that pre-dated the LUB computation stay as they are.
249+
if !is_var_in_set(new_vars, r0) {
250+
assert!(!r0.is_late_bound());
251+
debug!("generalize_region(r0={:?}): not new variable", r0);
252+
return r0;
253+
}
254+
255+
let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
256+
257+
// Variables created during LUB computation which are
258+
// *related* to regions that pre-date the LUB computation
259+
// stay as they are.
260+
if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
261+
debug!("generalize_region(r0={:?}): \
262+
non-new-variables found in {:?}",
263+
r0, tainted);
264+
assert!(!r0.is_late_bound());
265+
return r0;
266+
}
267+
268+
// Otherwise, the variable must be associated with at
269+
// least one of the variables representing bound regions
270+
// in both A and B. Replace the variable with the "first"
271+
// bound region from A that we find it to be associated
272+
// with.
273+
for (a_br, a_r) in a_map {
274+
if tainted.iter().any(|x| x == a_r) {
275+
debug!("generalize_region(r0={:?}): \
276+
replacing with {:?}, tainted={:?}",
277+
r0, *a_br, tainted);
278+
return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
279+
}
280+
}
281+
282+
span_bug!(
283+
span,
284+
"region {:?} is not associated with any bound region from A!",
285+
r0)
286+
}
287+
}
288+
289+
pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
290+
-> RelateResult<'tcx, Binder<T>>
291+
where T: Relate<'tcx>
292+
{
293+
debug!("higher_ranked_glb({:?}, {:?})",
294+
a, b);
295+
296+
// Make a snapshot so we can examine "all bindings that were
297+
// created as part of this type comparison".
298+
return self.infcx.commit_if_ok(|snapshot| {
299+
// Instantiate each bound region with a fresh region variable.
300+
let (a_with_fresh, a_map) =
301+
self.infcx.replace_late_bound_regions_with_fresh_var(
302+
self.trace.cause.span, HigherRankedType, a);
303+
let (b_with_fresh, b_map) =
304+
self.infcx.replace_late_bound_regions_with_fresh_var(
305+
self.trace.cause.span, HigherRankedType, b);
306+
let a_vars = var_ids(self, &a_map);
307+
let b_vars = var_ids(self, &b_map);
308+
309+
// Collect constraints.
310+
let result0 =
311+
self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
312+
let result0 =
313+
self.infcx.resolve_type_vars_if_possible(&result0);
314+
debug!("glb result0 = {:?}", result0);
315+
316+
// Generalize the regions appearing in result0 if possible
317+
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
318+
let span = self.trace.cause.span;
319+
let result1 =
320+
fold_regions_in(
321+
self.tcx(),
322+
&result0,
323+
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
324+
&new_vars,
325+
&a_map, &a_vars, &b_vars,
326+
r));
327+
328+
debug!("glb({:?},{:?}) = {:?}",
329+
a,
330+
b,
331+
result1);
332+
333+
Ok(ty::Binder(result1))
334+
});
335+
336+
fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
337+
span: Span,
338+
snapshot: &CombinedSnapshot,
339+
debruijn: ty::DebruijnIndex,
340+
new_vars: &[ty::RegionVid],
341+
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
342+
a_vars: &[ty::RegionVid],
343+
b_vars: &[ty::RegionVid],
344+
r0: ty::Region<'tcx>)
345+
-> ty::Region<'tcx> {
346+
if !is_var_in_set(new_vars, r0) {
347+
assert!(!r0.is_late_bound());
348+
return r0;
349+
}
350+
351+
let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
352+
353+
let mut a_r = None;
354+
let mut b_r = None;
355+
let mut only_new_vars = true;
356+
for r in &tainted {
357+
if is_var_in_set(a_vars, *r) {
358+
if a_r.is_some() {
359+
return fresh_bound_variable(infcx, debruijn);
360+
} else {
361+
a_r = Some(*r);
362+
}
363+
} else if is_var_in_set(b_vars, *r) {
364+
if b_r.is_some() {
365+
return fresh_bound_variable(infcx, debruijn);
366+
} else {
367+
b_r = Some(*r);
368+
}
369+
} else if !is_var_in_set(new_vars, *r) {
370+
only_new_vars = false;
371+
}
372+
}
373+
374+
// NB---I do not believe this algorithm computes
375+
// (necessarily) the GLB. As written it can
376+
// spuriously fail. In particular, if there is a case
377+
// like: |fn(&a)| and fn(fn(&b)), where a and b are
378+
// free, it will return fn(&c) where c = GLB(a,b). If
379+
// however this GLB is not defined, then the result is
380+
// an error, even though something like
381+
// "fn<X>(fn(&X))" where X is bound would be a
382+
// subtype of both of those.
383+
//
384+
// The problem is that if we were to return a bound
385+
// variable, we'd be computing a lower-bound, but not
386+
// necessarily the *greatest* lower-bound.
387+
//
388+
// Unfortunately, this problem is non-trivial to solve,
389+
// because we do not know at the time of computing the GLB
390+
// whether a GLB(a,b) exists or not, because we haven't
391+
// run region inference (or indeed, even fully computed
392+
// the region hierarchy!). The current algorithm seems to
393+
// works ok in practice.
394+
395+
if a_r.is_some() && b_r.is_some() && only_new_vars {
396+
// Related to exactly one bound variable from each fn:
397+
return rev_lookup(infcx, span, a_map, a_r.unwrap());
398+
} else if a_r.is_none() && b_r.is_none() {
399+
// Not related to bound variables from either fn:
400+
assert!(!r0.is_late_bound());
401+
return r0;
402+
} else {
403+
// Other:
404+
return fresh_bound_variable(infcx, debruijn);
405+
}
406+
}
407+
408+
fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
409+
span: Span,
410+
a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
411+
r: ty::Region<'tcx>) -> ty::Region<'tcx>
412+
{
413+
for (a_br, a_r) in a_map {
414+
if *a_r == r {
415+
return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br));
416+
}
417+
}
418+
span_bug!(
419+
span,
420+
"could not find original bound region for {:?}",
421+
r);
422+
}
423+
424+
fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
425+
debruijn: ty::DebruijnIndex)
426+
-> ty::Region<'tcx> {
427+
infcx.region_vars.new_bound(debruijn)
428+
}
429+
}
430+
}
431+
432+
fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
433+
map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
434+
-> Vec<ty::RegionVid> {
435+
map.iter()
436+
.map(|(_, &r)| match *r {
437+
ty::ReVar(r) => { r }
438+
_ => {
439+
span_bug!(
440+
fields.trace.cause.span,
441+
"found non-region-vid: {:?}",
442+
r);
443+
}
444+
})
445+
.collect()
446+
}
447+
448+
fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
449+
match *r {
450+
ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
451+
_ => false
452+
}
198453
}
199454

200455
fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,

src/librustc/infer/lub.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use super::InferCtxt;
12-
use super::Subtype;
1311
use super::combine::CombineFields;
12+
use super::InferCtxt;
1413
use super::lattice::{self, LatticeDir};
14+
use super::Subtype;
1515

1616
use traits::ObligationCause;
1717
use ty::{self, Ty, TyCtxt};
@@ -74,10 +74,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
7474
-> RelateResult<'tcx, ty::Binder<T>>
7575
where T: Relate<'tcx>
7676
{
77-
// Otherwise, we make the (overly strict) requirement that
78-
// the two sides are equal.
79-
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
80-
Ok(a.clone())
77+
self.fields.higher_ranked_lub(a, b, self.a_is_expected)
8178
}
8279
}
8380

0 commit comments

Comments
 (0)