Skip to content

Commit 23652ef

Browse files
committed
Pull out the fn-sig sub/lub/glb code and generalize it into a higher_ranked module. Also moves the docs to a more suitable place.
1 parent 058abcc commit 23652ef

File tree

8 files changed

+877
-701
lines changed

8 files changed

+877
-701
lines changed

src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,8 +1460,8 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
14601460
format!(" for {}in function call",
14611461
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
14621462
}
1463-
infer::LateBoundRegion(_, br, infer::FnType) => {
1464-
format!(" for {}in function type",
1463+
infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
1464+
format!(" for {}in generic type",
14651465
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
14661466
}
14671467
infer::EarlyBoundRegion(_, name) => {

src/librustc/middle/typeck/infer/glb.rs

Lines changed: 3 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,18 @@
1010

1111

1212
use middle::ty::{BuiltinBounds};
13-
use middle::ty::RegionVid;
1413
use middle::ty;
1514
use middle::typeck::infer::combine::*;
1615
use middle::typeck::infer::lattice::*;
1716
use middle::typeck::infer::equate::Equate;
18-
use middle::typeck::infer::fold_regions_in_sig;
19-
use middle::typeck::infer::LateBoundRegionConversionTime::FnType;
17+
use middle::typeck::infer::higher_ranked::HigherRankedRelations;
2018
use middle::typeck::infer::lub::Lub;
21-
use middle::typeck::infer::region_inference::RegionMark;
2219
use middle::typeck::infer::sub::Sub;
2320
use middle::typeck::infer::{cres, InferCtxt};
2421
use middle::typeck::infer::{TypeTrace, Subtype};
2522
use syntax::ast::{Many, Once, MutImmutable, MutMutable};
26-
use syntax::ast::{NormalFn, UnsafeFn, NodeId};
23+
use syntax::ast::{NormalFn, UnsafeFn};
2724
use syntax::ast::{Onceness, FnStyle};
28-
use util::common::{indenter};
29-
use util::nodemap::FnvHashMap;
3025
use util::ppaux::mt_to_string;
3126
use util::ppaux::Repr;
3227

@@ -128,139 +123,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
128123
}
129124

130125
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
131-
// Note: this is a subtle algorithm. For a full explanation,
132-
// please see the large comment in `region_inference.rs`.
133-
134-
debug!("{}.fn_sigs({}, {})",
135-
self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
136-
let _indenter = indenter();
137-
138-
// Make a mark so we can examine "all bindings that were
139-
// created as part of this type comparison".
140-
let mark = self.fields.infcx.region_vars.mark();
141-
142-
// Instantiate each bound region with a fresh region variable.
143-
let (a_with_fresh, a_map) =
144-
self.fields.infcx.replace_late_bound_regions_with_fresh_var(
145-
a.binder_id, self.trace().span(), FnType, a);
146-
let a_vars = var_ids(self, &a_map);
147-
let (b_with_fresh, b_map) =
148-
self.fields.infcx.replace_late_bound_regions_with_fresh_var(
149-
b.binder_id, self.trace().span(), FnType, b);
150-
let b_vars = var_ids(self, &b_map);
151-
152-
// Collect constraints.
153-
let sig0 = try!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
154-
debug!("sig0 = {}", sig0.repr(self.fields.infcx.tcx));
155-
156-
// Generalize the regions appearing in fn_ty0 if possible
157-
let new_vars =
158-
self.fields.infcx.region_vars.vars_created_since_mark(mark);
159-
let sig1 =
160-
fold_regions_in_sig(
161-
self.fields.infcx.tcx,
162-
&sig0,
163-
|r| {
164-
generalize_region(self,
165-
mark,
166-
new_vars.as_slice(),
167-
sig0.binder_id,
168-
&a_map,
169-
a_vars.as_slice(),
170-
b_vars.as_slice(),
171-
r)
172-
});
173-
debug!("sig1 = {}", sig1.repr(self.fields.infcx.tcx));
174-
return Ok(sig1);
175-
176-
fn generalize_region(this: &Glb,
177-
mark: RegionMark,
178-
new_vars: &[RegionVid],
179-
new_binder_id: NodeId,
180-
a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
181-
a_vars: &[RegionVid],
182-
b_vars: &[RegionVid],
183-
r0: ty::Region) -> ty::Region {
184-
if !is_var_in_set(new_vars, r0) {
185-
assert!(!r0.is_bound());
186-
return r0;
187-
}
188-
189-
let tainted = this.fields.infcx.region_vars.tainted(mark, r0);
190-
191-
let mut a_r = None;
192-
let mut b_r = None;
193-
let mut only_new_vars = true;
194-
for r in tainted.iter() {
195-
if is_var_in_set(a_vars, *r) {
196-
if a_r.is_some() {
197-
return fresh_bound_variable(this, new_binder_id);
198-
} else {
199-
a_r = Some(*r);
200-
}
201-
} else if is_var_in_set(b_vars, *r) {
202-
if b_r.is_some() {
203-
return fresh_bound_variable(this, new_binder_id);
204-
} else {
205-
b_r = Some(*r);
206-
}
207-
} else if !is_var_in_set(new_vars, *r) {
208-
only_new_vars = false;
209-
}
210-
}
211-
212-
// NB---I do not believe this algorithm computes
213-
// (necessarily) the GLB. As written it can
214-
// spuriously fail. In particular, if there is a case
215-
// like: |fn(&a)| and fn(fn(&b)), where a and b are
216-
// free, it will return fn(&c) where c = GLB(a,b). If
217-
// however this GLB is not defined, then the result is
218-
// an error, even though something like
219-
// "fn<X>(fn(&X))" where X is bound would be a
220-
// subtype of both of those.
221-
//
222-
// The problem is that if we were to return a bound
223-
// variable, we'd be computing a lower-bound, but not
224-
// necessarily the *greatest* lower-bound.
225-
//
226-
// Unfortunately, this problem is non-trivial to solve,
227-
// because we do not know at the time of computing the GLB
228-
// whether a GLB(a,b) exists or not, because we haven't
229-
// run region inference (or indeed, even fully computed
230-
// the region hierarchy!). The current algorithm seems to
231-
// works ok in practice.
232-
233-
if a_r.is_some() && b_r.is_some() && only_new_vars {
234-
// Related to exactly one bound variable from each fn:
235-
return rev_lookup(this, a_map, new_binder_id, a_r.unwrap());
236-
} else if a_r.is_none() && b_r.is_none() {
237-
// Not related to bound variables from either fn:
238-
assert!(!r0.is_bound());
239-
return r0;
240-
} else {
241-
// Other:
242-
return fresh_bound_variable(this, new_binder_id);
243-
}
244-
}
245-
246-
fn rev_lookup(this: &Glb,
247-
a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
248-
new_binder_id: NodeId,
249-
r: ty::Region) -> ty::Region
250-
{
251-
for (a_br, a_r) in a_map.iter() {
252-
if *a_r == r {
253-
return ty::ReLateBound(new_binder_id, *a_br);
254-
}
255-
}
256-
this.fields.infcx.tcx.sess.span_bug(
257-
this.fields.trace.origin.span(),
258-
format!("could not find original bound region for {}",
259-
r).as_slice())
260-
}
261-
262-
fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region {
263-
this.fields.infcx.region_vars.new_bound(binder_id)
264-
}
126+
self.higher_ranked_glb(a, b)
265127
}
266128
}

0 commit comments

Comments
 (0)