Skip to content

Commit 7226cda

Browse files
committed
make LUB/GLB of higher-ranked things actually do EQ
1 parent ca9cf35 commit 7226cda

File tree

3 files changed

+10
-259
lines changed

3 files changed

+10
-259
lines changed

src/librustc/infer/glb.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
7474
-> RelateResult<'tcx, ty::Binder<T>>
7575
where T: Relate<'tcx>
7676
{
77-
self.fields.higher_ranked_glb(a, b, self.a_is_expected)
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())
7881
}
7982
}
8083

src/librustc/infer/higher_ranked/mod.rs

-255
Original file line numberDiff line numberDiff line change
@@ -195,261 +195,6 @@ 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-
}
453198
}
454199

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

src/librustc/infer/lub.rs

+6-3
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::combine::CombineFields;
1211
use super::InferCtxt;
13-
use super::lattice::{self, LatticeDir};
1412
use super::Subtype;
13+
use super::combine::CombineFields;
14+
use super::lattice::{self, LatticeDir};
1515

1616
use traits::ObligationCause;
1717
use ty::{self, Ty, TyCtxt};
@@ -74,7 +74,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
7474
-> RelateResult<'tcx, ty::Binder<T>>
7575
where T: Relate<'tcx>
7676
{
77-
self.fields.higher_ranked_lub(a, b, self.a_is_expected)
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())
7881
}
7982
}
8083

0 commit comments

Comments
 (0)