]> git.proxmox.com Git - rustc.git/blob - src/librustc/middle/infer/region_inference/mod.rs
Imported Upstream version 1.0.0~beta.3
[rustc.git] / src / librustc / middle / infer / region_inference / mod.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! See README.md
12
13 pub use self::Constraint::*;
14 pub use self::Verify::*;
15 pub use self::UndoLogEntry::*;
16 pub use self::CombineMapType::*;
17 pub use self::RegionResolutionError::*;
18 pub use self::VarValue::*;
19 use self::Classification::*;
20
21 use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
22
23 use middle::region;
24 use middle::ty::{self, Ty};
25 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
26 use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
27 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
28 use middle::ty_relate::RelateResult;
29 use middle::graph;
30 use middle::graph::{Direction, NodeIndex};
31 use util::common::indenter;
32 use util::nodemap::{FnvHashMap, FnvHashSet};
33 use util::ppaux::{Repr, UserString};
34
35 use std::cell::{Cell, RefCell};
36 use std::cmp::Ordering::{self, Less, Greater, Equal};
37 use std::iter::repeat;
38 use std::u32;
39 use syntax::ast;
40
41 mod graphviz;
42
43 // A constraint that influences the inference process.
44 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
45 pub enum Constraint {
46 // One region variable is subregion of another
47 ConstrainVarSubVar(RegionVid, RegionVid),
48
49 // Concrete region is subregion of region variable
50 ConstrainRegSubVar(Region, RegionVid),
51
52 // Region variable is subregion of concrete region
53 ConstrainVarSubReg(RegionVid, Region),
54 }
55
56 // Something we have to verify after region inference is done, but
57 // which does not directly influence the inference process
58 pub enum Verify<'tcx> {
59 // VerifyRegSubReg(a, b): Verify that `a <= b`. Neither `a` nor
60 // `b` are inference variables.
61 VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region),
62
63 // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
64 // associated type) must outlive the region `R`. `T` is known to
65 // outlive `RS`. Therefore verify that `R <= RS[i]` for some
66 // `i`. Inference variables may be involved (but this verification
67 // step doesn't influence inference).
68 VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
69 }
70
71 #[derive(Clone, Debug, PartialEq, Eq)]
72 pub enum GenericKind<'tcx> {
73 Param(ty::ParamTy),
74 Projection(ty::ProjectionTy<'tcx>),
75 }
76
77 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
78 pub struct TwoRegions {
79 a: Region,
80 b: Region,
81 }
82
83 #[derive(Copy, Clone, PartialEq)]
84 pub enum UndoLogEntry {
85 OpenSnapshot,
86 CommitedSnapshot,
87 AddVar(RegionVid),
88 AddConstraint(Constraint),
89 AddVerify(usize),
90 AddGiven(ty::FreeRegion, ty::RegionVid),
91 AddCombination(CombineMapType, TwoRegions)
92 }
93
94 #[derive(Copy, Clone, PartialEq)]
95 pub enum CombineMapType {
96 Lub, Glb
97 }
98
99 #[derive(Clone, Debug)]
100 pub enum RegionResolutionError<'tcx> {
101 /// `ConcreteFailure(o, a, b)`:
102 ///
103 /// `o` requires that `a <= b`, but this does not hold
104 ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
105
106 /// `GenericBoundFailure(p, s, a, bs)
107 ///
108 /// The parameter/associated-type `p` must be known to outlive the lifetime
109 /// `a`, but it is only known to outlive `bs` (and none of the
110 /// regions in `bs` outlive `a`).
111 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec<Region>),
112
113 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
114 ///
115 /// Could not infer a value for `v` because `sub_r <= v` (due to
116 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
117 /// `sub_r <= sup_r` does not hold.
118 SubSupConflict(RegionVariableOrigin,
119 SubregionOrigin<'tcx>, Region,
120 SubregionOrigin<'tcx>, Region),
121
122 /// `SupSupConflict(v, origin1, r1, origin2, r2)`:
123 ///
124 /// Could not infer a value for `v` because `v <= r1` (due to
125 /// `origin1`) and `v <= r2` (due to `origin2`) and
126 /// `r1` and `r2` have no intersection.
127 SupSupConflict(RegionVariableOrigin,
128 SubregionOrigin<'tcx>, Region,
129 SubregionOrigin<'tcx>, Region),
130
131 /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive
132 /// more specific errors message by suggesting to the user where they
133 /// should put a lifetime. In those cases we process and put those errors
134 /// into `ProcessedErrors` before we do any reporting.
135 ProcessedErrors(Vec<RegionVariableOrigin>,
136 Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>,
137 Vec<SameRegions>),
138 }
139
140 /// SameRegions is used to group regions that we think are the same and would
141 /// like to indicate so to the user.
142 /// For example, the following function
143 /// ```
144 /// struct Foo { bar: int }
145 /// fn foo2<'a, 'b>(x: &'a Foo) -> &'b int {
146 /// &x.bar
147 /// }
148 /// ```
149 /// would report an error because we expect 'a and 'b to match, and so we group
150 /// 'a and 'b together inside a SameRegions struct
151 #[derive(Clone, Debug)]
152 pub struct SameRegions {
153 pub scope_id: ast::NodeId,
154 pub regions: Vec<BoundRegion>
155 }
156
157 impl SameRegions {
158 pub fn contains(&self, other: &BoundRegion) -> bool {
159 self.regions.contains(other)
160 }
161
162 pub fn push(&mut self, other: BoundRegion) {
163 self.regions.push(other);
164 }
165 }
166
167 pub type CombineMap = FnvHashMap<TwoRegions, RegionVid>;
168
169 pub struct RegionVarBindings<'a, 'tcx: 'a> {
170 tcx: &'a ty::ctxt<'tcx>,
171 var_origins: RefCell<Vec<RegionVariableOrigin>>,
172
173 // Constraints of the form `A <= B` introduced by the region
174 // checker. Here at least one of `A` and `B` must be a region
175 // variable.
176 constraints: RefCell<FnvHashMap<Constraint, SubregionOrigin<'tcx>>>,
177
178 // A "verify" is something that we need to verify after inference is
179 // done, but which does not directly affect inference in any way.
180 //
181 // An example is a `A <= B` where neither `A` nor `B` are
182 // inference variables.
183 verifys: RefCell<Vec<Verify<'tcx>>>,
184
185 // A "given" is a relationship that is known to hold. In particular,
186 // we often know from closure fn signatures that a particular free
187 // region must be a subregion of a region variable:
188 //
189 // foo.iter().filter(<'a> |x: &'a &'b T| ...)
190 //
191 // In situations like this, `'b` is in fact a region variable
192 // introduced by the call to `iter()`, and `'a` is a bound region
193 // on the closure (as indicated by the `<'a>` prefix). If we are
194 // naive, we wind up inferring that `'b` must be `'static`,
195 // because we require that it be greater than `'a` and we do not
196 // know what `'a` is precisely.
197 //
198 // This hashmap is used to avoid that naive scenario. Basically we
199 // record the fact that `'a <= 'b` is implied by the fn signature,
200 // and then ignore the constraint when solving equations. This is
201 // a bit of a hack but seems to work.
202 givens: RefCell<FnvHashSet<(ty::FreeRegion, ty::RegionVid)>>,
203
204 lubs: RefCell<CombineMap>,
205 glbs: RefCell<CombineMap>,
206 skolemization_count: Cell<u32>,
207 bound_count: Cell<u32>,
208
209 // The undo log records actions that might later be undone.
210 //
211 // Note: when the undo_log is empty, we are not actively
212 // snapshotting. When the `start_snapshot()` method is called, we
213 // push an OpenSnapshot entry onto the list to indicate that we
214 // are now actively snapshotting. The reason for this is that
215 // otherwise we end up adding entries for things like the lower
216 // bound on a variable and so forth, which can never be rolled
217 // back.
218 undo_log: RefCell<Vec<UndoLogEntry>>,
219
220 // This contains the results of inference. It begins as an empty
221 // option and only acquires a value after inference is complete.
222 values: RefCell<Option<Vec<VarValue>>>,
223 }
224
225 #[derive(Debug)]
226 pub struct RegionSnapshot {
227 length: usize,
228 skolemization_count: u32,
229 }
230
231 impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
232 pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> {
233 RegionVarBindings {
234 tcx: tcx,
235 var_origins: RefCell::new(Vec::new()),
236 values: RefCell::new(None),
237 constraints: RefCell::new(FnvHashMap()),
238 verifys: RefCell::new(Vec::new()),
239 givens: RefCell::new(FnvHashSet()),
240 lubs: RefCell::new(FnvHashMap()),
241 glbs: RefCell::new(FnvHashMap()),
242 skolemization_count: Cell::new(0),
243 bound_count: Cell::new(0),
244 undo_log: RefCell::new(Vec::new())
245 }
246 }
247
248 fn in_snapshot(&self) -> bool {
249 !self.undo_log.borrow().is_empty()
250 }
251
252 pub fn start_snapshot(&self) -> RegionSnapshot {
253 let length = self.undo_log.borrow().len();
254 debug!("RegionVarBindings: start_snapshot({})", length);
255 self.undo_log.borrow_mut().push(OpenSnapshot);
256 RegionSnapshot { length: length, skolemization_count: self.skolemization_count.get() }
257 }
258
259 pub fn commit(&self, snapshot: RegionSnapshot) {
260 debug!("RegionVarBindings: commit({})", snapshot.length);
261 assert!(self.undo_log.borrow().len() > snapshot.length);
262 assert!((*self.undo_log.borrow())[snapshot.length] == OpenSnapshot);
263
264 let mut undo_log = self.undo_log.borrow_mut();
265 if snapshot.length == 0 {
266 undo_log.truncate(0);
267 } else {
268 (*undo_log)[snapshot.length] = CommitedSnapshot;
269 }
270 self.skolemization_count.set(snapshot.skolemization_count);
271 }
272
273 pub fn rollback_to(&self, snapshot: RegionSnapshot) {
274 debug!("RegionVarBindings: rollback_to({:?})", snapshot);
275 let mut undo_log = self.undo_log.borrow_mut();
276 assert!(undo_log.len() > snapshot.length);
277 assert!((*undo_log)[snapshot.length] == OpenSnapshot);
278 while undo_log.len() > snapshot.length + 1 {
279 match undo_log.pop().unwrap() {
280 OpenSnapshot => {
281 panic!("Failure to observe stack discipline");
282 }
283 CommitedSnapshot => { }
284 AddVar(vid) => {
285 let mut var_origins = self.var_origins.borrow_mut();
286 var_origins.pop().unwrap();
287 assert_eq!(var_origins.len(), vid.index as usize);
288 }
289 AddConstraint(ref constraint) => {
290 self.constraints.borrow_mut().remove(constraint);
291 }
292 AddVerify(index) => {
293 self.verifys.borrow_mut().pop();
294 assert_eq!(self.verifys.borrow().len(), index);
295 }
296 AddGiven(sub, sup) => {
297 self.givens.borrow_mut().remove(&(sub, sup));
298 }
299 AddCombination(Glb, ref regions) => {
300 self.glbs.borrow_mut().remove(regions);
301 }
302 AddCombination(Lub, ref regions) => {
303 self.lubs.borrow_mut().remove(regions);
304 }
305 }
306 }
307 let c = undo_log.pop().unwrap();
308 assert!(c == OpenSnapshot);
309 self.skolemization_count.set(snapshot.skolemization_count);
310 }
311
312 pub fn num_vars(&self) -> u32 {
313 let len = self.var_origins.borrow().len();
314 // enforce no overflow
315 assert!(len as u32 as usize == len);
316 len as u32
317 }
318
319 pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
320 let id = self.num_vars();
321 self.var_origins.borrow_mut().push(origin.clone());
322 let vid = RegionVid { index: id };
323 if self.in_snapshot() {
324 self.undo_log.borrow_mut().push(AddVar(vid));
325 }
326 debug!("created new region variable {:?} with origin {}",
327 vid, origin.repr(self.tcx));
328 return vid;
329 }
330
331 /// Creates a new skolemized region. Skolemized regions are fresh
332 /// regions used when performing higher-ranked computations. They
333 /// must be used in a very particular way and are never supposed
334 /// to "escape" out into error messages or the code at large.
335 ///
336 /// The idea is to always create a snapshot. Skolemized regions
337 /// can be created in the context of this snapshot, but once the
338 /// snapshot is committed or rolled back, their numbers will be
339 /// recycled, so you must be finished with them. See the extensive
340 /// comments in `higher_ranked.rs` to see how it works (in
341 /// particular, the subtyping comparison).
342 ///
343 /// The `snapshot` argument to this function is not really used;
344 /// it's just there to make it explicit which snapshot bounds the
345 /// skolemized region that results.
346 pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region {
347 assert!(self.in_snapshot());
348 assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
349
350 let sc = self.skolemization_count.get();
351 self.skolemization_count.set(sc + 1);
352 ReInfer(ReSkolemized(sc, br))
353 }
354
355 pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
356 // Creates a fresh bound variable for use in GLB computations.
357 // See discussion of GLB computation in the large comment at
358 // the top of this file for more details.
359 //
360 // This computation is potentially wrong in the face of
361 // rollover. It's conceivable, if unlikely, that one might
362 // wind up with accidental capture for nested functions in
363 // that case, if the outer function had bound regions created
364 // a very long time before and the inner function somehow
365 // wound up rolling over such that supposedly fresh
366 // identifiers were in fact shadowed. For now, we just assert
367 // that there is no rollover -- eventually we should try to be
368 // robust against this possibility, either by checking the set
369 // of bound identifiers that appear in a given expression and
370 // ensure that we generate one that is distinct, or by
371 // changing the representation of bound regions in a fn
372 // declaration
373
374 let sc = self.bound_count.get();
375 self.bound_count.set(sc + 1);
376
377 if sc >= self.bound_count.get() {
378 self.tcx.sess.bug("rollover in RegionInference new_bound()");
379 }
380
381 ReLateBound(debruijn, BrFresh(sc))
382 }
383
384 fn values_are_none(&self) -> bool {
385 self.values.borrow().is_none()
386 }
387
388 fn add_constraint(&self,
389 constraint: Constraint,
390 origin: SubregionOrigin<'tcx>) {
391 // cannot add constraints once regions are resolved
392 assert!(self.values_are_none());
393
394 debug!("RegionVarBindings: add_constraint({})",
395 constraint.repr(self.tcx));
396
397 if self.constraints.borrow_mut().insert(constraint, origin).is_none() {
398 if self.in_snapshot() {
399 self.undo_log.borrow_mut().push(AddConstraint(constraint));
400 }
401 }
402 }
403
404 fn add_verify(&self,
405 verify: Verify<'tcx>) {
406 // cannot add verifys once regions are resolved
407 assert!(self.values_are_none());
408
409 debug!("RegionVarBindings: add_verify({})",
410 verify.repr(self.tcx));
411
412 let mut verifys = self.verifys.borrow_mut();
413 let index = verifys.len();
414 verifys.push(verify);
415 if self.in_snapshot() {
416 self.undo_log.borrow_mut().push(AddVerify(index));
417 }
418 }
419
420 pub fn add_given(&self,
421 sub: ty::FreeRegion,
422 sup: ty::RegionVid) {
423 // cannot add givens once regions are resolved
424 assert!(self.values_are_none());
425
426 let mut givens = self.givens.borrow_mut();
427 if givens.insert((sub, sup)) {
428 debug!("add_given({} <= {:?})",
429 sub.repr(self.tcx),
430 sup);
431
432 self.undo_log.borrow_mut().push(AddGiven(sub, sup));
433 }
434 }
435
436 pub fn make_eqregion(&self,
437 origin: SubregionOrigin<'tcx>,
438 sub: Region,
439 sup: Region) {
440 if sub != sup {
441 // Eventually, it would be nice to add direct support for
442 // equating regions.
443 self.make_subregion(origin.clone(), sub, sup);
444 self.make_subregion(origin, sup, sub);
445 }
446 }
447
448 pub fn make_subregion(&self,
449 origin: SubregionOrigin<'tcx>,
450 sub: Region,
451 sup: Region) {
452 // cannot add constraints once regions are resolved
453 assert!(self.values_are_none());
454
455 debug!("RegionVarBindings: make_subregion({}, {}) due to {}",
456 sub.repr(self.tcx),
457 sup.repr(self.tcx),
458 origin.repr(self.tcx));
459
460 match (sub, sup) {
461 (ReEarlyBound(..), ReEarlyBound(..)) => {
462 // This case is used only to make sure that explicitly-specified
463 // `Self` types match the real self type in implementations.
464 //
465 // FIXME(NDM) -- we really shouldn't be comparing bound things
466 self.add_verify(VerifyRegSubReg(origin, sub, sup));
467 }
468 (ReEarlyBound(..), _) |
469 (ReLateBound(..), _) |
470 (_, ReEarlyBound(..)) |
471 (_, ReLateBound(..)) => {
472 self.tcx.sess.span_bug(
473 origin.span(),
474 &format!("cannot relate bound region: {} <= {}",
475 sub.repr(self.tcx),
476 sup.repr(self.tcx)));
477 }
478 (_, ReStatic) => {
479 // all regions are subregions of static, so we can ignore this
480 }
481 (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => {
482 self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
483 }
484 (r, ReInfer(ReVar(sup_id))) => {
485 self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
486 }
487 (ReInfer(ReVar(sub_id)), r) => {
488 self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
489 }
490 _ => {
491 self.add_verify(VerifyRegSubReg(origin, sub, sup));
492 }
493 }
494 }
495
496 /// See `Verify::VerifyGenericBound`
497 pub fn verify_generic_bound(&self,
498 origin: SubregionOrigin<'tcx>,
499 kind: GenericKind<'tcx>,
500 sub: Region,
501 sups: Vec<Region>) {
502 self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
503 }
504
505 pub fn lub_regions(&self,
506 origin: SubregionOrigin<'tcx>,
507 a: Region,
508 b: Region)
509 -> Region {
510 // cannot add constraints once regions are resolved
511 assert!(self.values_are_none());
512
513 debug!("RegionVarBindings: lub_regions({}, {})",
514 a.repr(self.tcx),
515 b.repr(self.tcx));
516 match (a, b) {
517 (ReStatic, _) | (_, ReStatic) => {
518 ReStatic // nothing lives longer than static
519 }
520
521 _ => {
522 self.combine_vars(
523 Lub, a, b, origin.clone(),
524 |this, old_r, new_r|
525 this.make_subregion(origin.clone(), old_r, new_r))
526 }
527 }
528 }
529
530 pub fn glb_regions(&self,
531 origin: SubregionOrigin<'tcx>,
532 a: Region,
533 b: Region)
534 -> Region {
535 // cannot add constraints once regions are resolved
536 assert!(self.values_are_none());
537
538 debug!("RegionVarBindings: glb_regions({}, {})",
539 a.repr(self.tcx),
540 b.repr(self.tcx));
541 match (a, b) {
542 (ReStatic, r) | (r, ReStatic) => {
543 // static lives longer than everything else
544 r
545 }
546
547 _ => {
548 self.combine_vars(
549 Glb, a, b, origin.clone(),
550 |this, old_r, new_r|
551 this.make_subregion(origin.clone(), new_r, old_r))
552 }
553 }
554 }
555
556 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
557 match *self.values.borrow() {
558 None => {
559 self.tcx.sess.span_bug(
560 (*self.var_origins.borrow())[rid.index as usize].span(),
561 "attempt to resolve region variable before values have \
562 been computed!")
563 }
564 Some(ref values) => {
565 let r = lookup(values, rid);
566 debug!("resolve_var({:?}) = {}", rid, r.repr(self.tcx));
567 r
568 }
569 }
570 }
571
572 fn combine_map(&self, t: CombineMapType)
573 -> &RefCell<CombineMap> {
574 match t {
575 Glb => &self.glbs,
576 Lub => &self.lubs,
577 }
578 }
579
580 pub fn combine_vars<F>(&self,
581 t: CombineMapType,
582 a: Region,
583 b: Region,
584 origin: SubregionOrigin<'tcx>,
585 mut relate: F)
586 -> Region where
587 F: FnMut(&RegionVarBindings<'a, 'tcx>, Region, Region),
588 {
589 let vars = TwoRegions { a: a, b: b };
590 match self.combine_map(t).borrow().get(&vars) {
591 Some(&c) => {
592 return ReInfer(ReVar(c));
593 }
594 None => {}
595 }
596 let c = self.new_region_var(MiscVariable(origin.span()));
597 self.combine_map(t).borrow_mut().insert(vars, c);
598 if self.in_snapshot() {
599 self.undo_log.borrow_mut().push(AddCombination(t, vars));
600 }
601 relate(self, a, ReInfer(ReVar(c)));
602 relate(self, b, ReInfer(ReVar(c)));
603 debug!("combine_vars() c={:?}", c);
604 ReInfer(ReVar(c))
605 }
606
607 pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot)
608 -> Vec<RegionVid>
609 {
610 self.undo_log.borrow()[mark.length..]
611 .iter()
612 .filter_map(|&elt| match elt {
613 AddVar(vid) => Some(vid),
614 _ => None
615 })
616 .collect()
617 }
618
619 /// Computes all regions that have been related to `r0` in any way since the mark `mark` was
620 /// made---`r0` itself will be the first entry. This is used when checking whether skolemized
621 /// regions are being improperly related to other regions.
622 pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
623 debug!("tainted(mark={:?}, r0={})", mark, r0.repr(self.tcx));
624 let _indenter = indenter();
625
626 // `result_set` acts as a worklist: we explore all outgoing
627 // edges and add any new regions we find to result_set. This
628 // is not a terribly efficient implementation.
629 let mut result_set = vec!(r0);
630 let mut result_index = 0;
631 while result_index < result_set.len() {
632 // nb: can't use usize::range() here because result_set grows
633 let r = result_set[result_index];
634 debug!("result_index={}, r={:?}", result_index, r);
635
636 for undo_entry in
637 self.undo_log.borrow()[mark.length..].iter()
638 {
639 match undo_entry {
640 &AddConstraint(ConstrainVarSubVar(a, b)) => {
641 consider_adding_bidirectional_edges(
642 &mut result_set, r,
643 ReInfer(ReVar(a)), ReInfer(ReVar(b)));
644 }
645 &AddConstraint(ConstrainRegSubVar(a, b)) => {
646 consider_adding_bidirectional_edges(
647 &mut result_set, r,
648 a, ReInfer(ReVar(b)));
649 }
650 &AddConstraint(ConstrainVarSubReg(a, b)) => {
651 consider_adding_bidirectional_edges(
652 &mut result_set, r,
653 ReInfer(ReVar(a)), b);
654 }
655 &AddGiven(a, b) => {
656 consider_adding_bidirectional_edges(
657 &mut result_set, r,
658 ReFree(a), ReInfer(ReVar(b)));
659 }
660 &AddVerify(i) => {
661 match (*self.verifys.borrow())[i] {
662 VerifyRegSubReg(_, a, b) => {
663 consider_adding_bidirectional_edges(
664 &mut result_set, r,
665 a, b);
666 }
667 VerifyGenericBound(_, _, a, ref bs) => {
668 for &b in bs {
669 consider_adding_bidirectional_edges(
670 &mut result_set, r,
671 a, b);
672 }
673 }
674 }
675 }
676 &AddCombination(..) |
677 &AddVar(..) |
678 &OpenSnapshot |
679 &CommitedSnapshot => {
680 }
681 }
682 }
683
684 result_index += 1;
685 }
686
687 return result_set;
688
689 fn consider_adding_bidirectional_edges(result_set: &mut Vec<Region>,
690 r: Region,
691 r1: Region,
692 r2: Region) {
693 consider_adding_directed_edge(result_set, r, r1, r2);
694 consider_adding_directed_edge(result_set, r, r2, r1);
695 }
696
697 fn consider_adding_directed_edge(result_set: &mut Vec<Region>,
698 r: Region,
699 r1: Region,
700 r2: Region) {
701 if r == r1 {
702 // Clearly, this is potentially inefficient.
703 if !result_set.iter().any(|x| *x == r2) {
704 result_set.push(r2);
705 }
706 }
707 }
708 }
709
710 /// This function performs the actual region resolution. It must be
711 /// called after all constraints have been added. It performs a
712 /// fixed-point iteration to find region values which satisfy all
713 /// constraints, assuming such values can be found; if they cannot,
714 /// errors are reported.
715 pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> {
716 debug!("RegionVarBindings: resolve_regions()");
717 let mut errors = vec!();
718 let v = self.infer_variable_values(&mut errors, subject_node);
719 *self.values.borrow_mut() = Some(v);
720 errors
721 }
722
723 fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
724 self.tcx.region_maps.is_subregion_of(sub, sup)
725 }
726
727 fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
728 match (a, b) {
729 (ReLateBound(..), _) |
730 (_, ReLateBound(..)) |
731 (ReEarlyBound(..), _) |
732 (_, ReEarlyBound(..)) => {
733 self.tcx.sess.bug(
734 &format!("cannot relate bound region: LUB({}, {})",
735 a.repr(self.tcx),
736 b.repr(self.tcx)));
737 }
738
739 (ReStatic, _) | (_, ReStatic) => {
740 ReStatic // nothing lives longer than static
741 }
742
743 (ReEmpty, r) | (r, ReEmpty) => {
744 r // everything lives longer than empty
745 }
746
747 (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
748 self.tcx.sess.span_bug(
749 (*self.var_origins.borrow())[v_id.index as usize].span(),
750 &format!("lub_concrete_regions invoked with \
751 non-concrete regions: {:?}, {:?}",
752 a,
753 b));
754 }
755
756 (ReFree(ref fr), ReScope(s_id)) |
757 (ReScope(s_id), ReFree(ref fr)) => {
758 let f = ReFree(*fr);
759 // A "free" region can be interpreted as "some region
760 // at least as big as the block fr.scope_id". So, we can
761 // reasonably compare free regions and scopes:
762 let fr_scope = fr.scope.to_code_extent();
763 let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id);
764
765 if r_id == fr_scope {
766 // if the free region's scope `fr.scope_id` is bigger than
767 // the scope region `s_id`, then the LUB is the free
768 // region itself:
769 f
770 } else {
771 // otherwise, we don't know what the free region is,
772 // so we must conservatively say the LUB is static:
773 ReStatic
774 }
775 }
776
777 (ReScope(a_id), ReScope(b_id)) => {
778 // The region corresponding to an outer block is a
779 // subtype of the region corresponding to an inner
780 // block.
781 ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
782 }
783
784 (ReFree(ref a_fr), ReFree(ref b_fr)) => {
785 self.lub_free_regions(a_fr, b_fr)
786 }
787
788 // For these types, we cannot define any additional
789 // relationship:
790 (ReInfer(ReSkolemized(..)), _) |
791 (_, ReInfer(ReSkolemized(..))) => {
792 if a == b {a} else {ReStatic}
793 }
794 }
795 }
796
797 /// Computes a region that encloses both free region arguments. Guarantee that if the same two
798 /// regions are given as argument, in any order, a consistent result is returned.
799 fn lub_free_regions(&self,
800 a: &FreeRegion,
801 b: &FreeRegion)
802 -> ty::Region
803 {
804 return match a.cmp(b) {
805 Less => helper(self, a, b),
806 Greater => helper(self, b, a),
807 Equal => ty::ReFree(*a)
808 };
809
810 fn helper(this: &RegionVarBindings,
811 a: &FreeRegion,
812 b: &FreeRegion) -> ty::Region
813 {
814 if this.tcx.region_maps.sub_free_region(*a, *b) {
815 ty::ReFree(*b)
816 } else if this.tcx.region_maps.sub_free_region(*b, *a) {
817 ty::ReFree(*a)
818 } else {
819 ty::ReStatic
820 }
821 }
822 }
823
824 fn glb_concrete_regions(&self,
825 a: Region,
826 b: Region)
827 -> RelateResult<'tcx, Region>
828 {
829 debug!("glb_concrete_regions({:?}, {:?})", a, b);
830 match (a, b) {
831 (ReLateBound(..), _) |
832 (_, ReLateBound(..)) |
833 (ReEarlyBound(..), _) |
834 (_, ReEarlyBound(..)) => {
835 self.tcx.sess.bug(
836 &format!("cannot relate bound region: GLB({}, {})",
837 a.repr(self.tcx),
838 b.repr(self.tcx)));
839 }
840
841 (ReStatic, r) | (r, ReStatic) => {
842 // static lives longer than everything else
843 Ok(r)
844 }
845
846 (ReEmpty, _) | (_, ReEmpty) => {
847 // nothing lives shorter than everything else
848 Ok(ReEmpty)
849 }
850
851 (ReInfer(ReVar(v_id)), _) |
852 (_, ReInfer(ReVar(v_id))) => {
853 self.tcx.sess.span_bug(
854 (*self.var_origins.borrow())[v_id.index as usize].span(),
855 &format!("glb_concrete_regions invoked with \
856 non-concrete regions: {:?}, {:?}",
857 a,
858 b));
859 }
860
861 (ReFree(ref fr), ReScope(s_id)) |
862 (ReScope(s_id), ReFree(ref fr)) => {
863 let s = ReScope(s_id);
864 // Free region is something "at least as big as
865 // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
866 // than the scope `s_id`, then we can say that the GLB
867 // is the scope `s_id`. Otherwise, as we do not know
868 // big the free region is precisely, the GLB is undefined.
869 let fr_scope = fr.scope.to_code_extent();
870 if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope {
871 Ok(s)
872 } else {
873 Err(ty::terr_regions_no_overlap(b, a))
874 }
875 }
876
877 (ReScope(a_id), ReScope(b_id)) => {
878 self.intersect_scopes(a, b, a_id, b_id)
879 }
880
881 (ReFree(ref a_fr), ReFree(ref b_fr)) => {
882 self.glb_free_regions(a_fr, b_fr)
883 }
884
885 // For these types, we cannot define any additional
886 // relationship:
887 (ReInfer(ReSkolemized(..)), _) |
888 (_, ReInfer(ReSkolemized(..))) => {
889 if a == b {
890 Ok(a)
891 } else {
892 Err(ty::terr_regions_no_overlap(b, a))
893 }
894 }
895 }
896 }
897
898 /// Computes a region that is enclosed by both free region arguments, if any. Guarantees that
899 /// if the same two regions are given as argument, in any order, a consistent result is
900 /// returned.
901 fn glb_free_regions(&self,
902 a: &FreeRegion,
903 b: &FreeRegion)
904 -> RelateResult<'tcx, ty::Region>
905 {
906 return match a.cmp(b) {
907 Less => helper(self, a, b),
908 Greater => helper(self, b, a),
909 Equal => Ok(ty::ReFree(*a))
910 };
911
912 fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
913 a: &FreeRegion,
914 b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
915 {
916 if this.tcx.region_maps.sub_free_region(*a, *b) {
917 Ok(ty::ReFree(*a))
918 } else if this.tcx.region_maps.sub_free_region(*b, *a) {
919 Ok(ty::ReFree(*b))
920 } else {
921 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
922 a.scope.to_code_extent(),
923 b.scope.to_code_extent())
924 }
925 }
926 }
927
928 fn intersect_scopes(&self,
929 region_a: ty::Region,
930 region_b: ty::Region,
931 scope_a: region::CodeExtent,
932 scope_b: region::CodeExtent)
933 -> RelateResult<'tcx, Region>
934 {
935 // We want to generate the intersection of two
936 // scopes or two free regions. So, if one of
937 // these scopes is a subscope of the other, return
938 // it. Otherwise fail.
939 debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
940 scope_a, scope_b, region_a, region_b);
941 let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
942 if r_id == scope_a {
943 Ok(ReScope(scope_b))
944 } else if r_id == scope_b {
945 Ok(ReScope(scope_a))
946 } else {
947 Err(ty::terr_regions_no_overlap(region_a, region_b))
948 }
949 }
950 }
951
952 // ______________________________________________________________________
953
954 #[derive(Copy, Clone, PartialEq, Debug)]
955 enum Classification { Expanding, Contracting }
956
957 #[derive(Copy, Clone)]
958 pub enum VarValue { NoValue, Value(Region), ErrorValue }
959
960 struct VarData {
961 classification: Classification,
962 value: VarValue,
963 }
964
965 struct RegionAndOrigin<'tcx> {
966 region: Region,
967 origin: SubregionOrigin<'tcx>,
968 }
969
970 type RegionGraph = graph::Graph<(), Constraint>;
971
972 impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
973 fn infer_variable_values(&self,
974 errors: &mut Vec<RegionResolutionError<'tcx>>,
975 subject: ast::NodeId) -> Vec<VarValue>
976 {
977 let mut var_data = self.construct_var_data();
978
979 // Dorky hack to cause `dump_constraints` to only get called
980 // if debug mode is enabled:
981 debug!("----() End constraint listing {:?}---", self.dump_constraints());
982 graphviz::maybe_print_constraints_for(self, subject);
983
984 self.expansion(&mut var_data);
985 self.contraction(&mut var_data);
986 let values =
987 self.extract_values_and_collect_conflicts(&var_data[..],
988 errors);
989 self.collect_concrete_region_errors(&values, errors);
990 values
991 }
992
993 fn construct_var_data(&self) -> Vec<VarData> {
994 (0..self.num_vars() as usize).map(|_| {
995 VarData {
996 // All nodes are initially classified as contracting; during
997 // the expansion phase, we will shift the classification for
998 // those nodes that have a concrete region predecessor to
999 // Expanding.
1000 classification: Contracting,
1001 value: NoValue,
1002 }
1003 }).collect()
1004 }
1005
1006 fn dump_constraints(&self) {
1007 debug!("----() Start constraint listing ()----");
1008 for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
1009 debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
1010 }
1011 }
1012
1013 fn expansion(&self, var_data: &mut [VarData]) {
1014 self.iterate_until_fixed_point("Expansion", |constraint| {
1015 debug!("expansion: constraint={} origin={}",
1016 constraint.repr(self.tcx),
1017 self.constraints.borrow()
1018 .get(constraint)
1019 .unwrap()
1020 .repr(self.tcx));
1021 match *constraint {
1022 ConstrainRegSubVar(a_region, b_vid) => {
1023 let b_data = &mut var_data[b_vid.index as usize];
1024 self.expand_node(a_region, b_vid, b_data)
1025 }
1026 ConstrainVarSubVar(a_vid, b_vid) => {
1027 match var_data[a_vid.index as usize].value {
1028 NoValue | ErrorValue => false,
1029 Value(a_region) => {
1030 let b_node = &mut var_data[b_vid.index as usize];
1031 self.expand_node(a_region, b_vid, b_node)
1032 }
1033 }
1034 }
1035 ConstrainVarSubReg(..) => {
1036 // This is a contraction constraint. Ignore it.
1037 false
1038 }
1039 }
1040 })
1041 }
1042
1043 fn expand_node(&self,
1044 a_region: Region,
1045 b_vid: RegionVid,
1046 b_data: &mut VarData)
1047 -> bool
1048 {
1049 debug!("expand_node({}, {:?} == {})",
1050 a_region.repr(self.tcx),
1051 b_vid,
1052 b_data.value.repr(self.tcx));
1053
1054 // Check if this relationship is implied by a given.
1055 match a_region {
1056 ty::ReFree(fr) => {
1057 if self.givens.borrow().contains(&(fr, b_vid)) {
1058 debug!("given");
1059 return false;
1060 }
1061 }
1062 _ => { }
1063 }
1064
1065 b_data.classification = Expanding;
1066 match b_data.value {
1067 NoValue => {
1068 debug!("Setting initial value of {:?} to {}",
1069 b_vid, a_region.repr(self.tcx));
1070
1071 b_data.value = Value(a_region);
1072 return true;
1073 }
1074
1075 Value(cur_region) => {
1076 let lub = self.lub_concrete_regions(a_region, cur_region);
1077 if lub == cur_region {
1078 return false;
1079 }
1080
1081 debug!("Expanding value of {:?} from {} to {}",
1082 b_vid,
1083 cur_region.repr(self.tcx),
1084 lub.repr(self.tcx));
1085
1086 b_data.value = Value(lub);
1087 return true;
1088 }
1089
1090 ErrorValue => {
1091 return false;
1092 }
1093 }
1094 }
1095
1096 fn contraction(&self,
1097 var_data: &mut [VarData]) {
1098 self.iterate_until_fixed_point("Contraction", |constraint| {
1099 debug!("contraction: constraint={} origin={}",
1100 constraint.repr(self.tcx),
1101 self.constraints.borrow()
1102 .get(constraint)
1103 .unwrap()
1104 .repr(self.tcx));
1105 match *constraint {
1106 ConstrainRegSubVar(..) => {
1107 // This is an expansion constraint. Ignore.
1108 false
1109 }
1110 ConstrainVarSubVar(a_vid, b_vid) => {
1111 match var_data[b_vid.index as usize].value {
1112 NoValue | ErrorValue => false,
1113 Value(b_region) => {
1114 let a_data = &mut var_data[a_vid.index as usize];
1115 self.contract_node(a_vid, a_data, b_region)
1116 }
1117 }
1118 }
1119 ConstrainVarSubReg(a_vid, b_region) => {
1120 let a_data = &mut var_data[a_vid.index as usize];
1121 self.contract_node(a_vid, a_data, b_region)
1122 }
1123 }
1124 })
1125 }
1126
1127 fn contract_node(&self,
1128 a_vid: RegionVid,
1129 a_data: &mut VarData,
1130 b_region: Region)
1131 -> bool {
1132 debug!("contract_node({:?} == {}/{:?}, {})",
1133 a_vid, a_data.value.repr(self.tcx),
1134 a_data.classification, b_region.repr(self.tcx));
1135
1136 return match a_data.value {
1137 NoValue => {
1138 assert_eq!(a_data.classification, Contracting);
1139 a_data.value = Value(b_region);
1140 true // changed
1141 }
1142
1143 ErrorValue => false, // no change
1144
1145 Value(a_region) => {
1146 match a_data.classification {
1147 Expanding => check_node(self, a_vid, a_data, a_region, b_region),
1148 Contracting => adjust_node(self, a_vid, a_data, a_region, b_region),
1149 }
1150 }
1151 };
1152
1153 fn check_node(this: &RegionVarBindings,
1154 a_vid: RegionVid,
1155 a_data: &mut VarData,
1156 a_region: Region,
1157 b_region: Region)
1158 -> bool {
1159 if !this.is_subregion_of(a_region, b_region) {
1160 debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
1161 a_vid,
1162 a_region.repr(this.tcx),
1163 b_region.repr(this.tcx));
1164 a_data.value = ErrorValue;
1165 }
1166 false
1167 }
1168
1169 fn adjust_node(this: &RegionVarBindings,
1170 a_vid: RegionVid,
1171 a_data: &mut VarData,
1172 a_region: Region,
1173 b_region: Region)
1174 -> bool {
1175 match this.glb_concrete_regions(a_region, b_region) {
1176 Ok(glb) => {
1177 if glb == a_region {
1178 false
1179 } else {
1180 debug!("Contracting value of {:?} from {} to {}",
1181 a_vid,
1182 a_region.repr(this.tcx),
1183 glb.repr(this.tcx));
1184 a_data.value = Value(glb);
1185 true
1186 }
1187 }
1188 Err(_) => {
1189 debug!("Setting {:?} to ErrorValue: no glb of {}, {}",
1190 a_vid,
1191 a_region.repr(this.tcx),
1192 b_region.repr(this.tcx));
1193 a_data.value = ErrorValue;
1194 false
1195 }
1196 }
1197 }
1198 }
1199
1200 fn collect_concrete_region_errors(&self,
1201 values: &Vec<VarValue>,
1202 errors: &mut Vec<RegionResolutionError<'tcx>>)
1203 {
1204 let mut reg_reg_dups = FnvHashSet();
1205 for verify in &*self.verifys.borrow() {
1206 match *verify {
1207 VerifyRegSubReg(ref origin, sub, sup) => {
1208 if self.is_subregion_of(sub, sup) {
1209 continue;
1210 }
1211
1212 if !reg_reg_dups.insert((sub, sup)) {
1213 continue;
1214 }
1215
1216 debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
1217 sub.repr(self.tcx),
1218 sup.repr(self.tcx));
1219 errors.push(ConcreteFailure((*origin).clone(), sub, sup));
1220 }
1221
1222 VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
1223 let sub = normalize(values, sub);
1224 if sups.iter()
1225 .map(|&sup| normalize(values, sup))
1226 .any(|sup| self.is_subregion_of(sub, sup))
1227 {
1228 continue;
1229 }
1230
1231 let sups = sups.iter().map(|&sup| normalize(values, sup))
1232 .collect();
1233 errors.push(
1234 GenericBoundFailure(
1235 (*origin).clone(), kind.clone(), sub, sups));
1236 }
1237 }
1238 }
1239 }
1240
1241 fn extract_values_and_collect_conflicts(
1242 &self,
1243 var_data: &[VarData],
1244 errors: &mut Vec<RegionResolutionError<'tcx>>)
1245 -> Vec<VarValue>
1246 {
1247 debug!("extract_values_and_collect_conflicts()");
1248
1249 // This is the best way that I have found to suppress
1250 // duplicate and related errors. Basically we keep a set of
1251 // flags for every node. Whenever an error occurs, we will
1252 // walk some portion of the graph looking to find pairs of
1253 // conflicting regions to report to the user. As we walk, we
1254 // trip the flags from false to true, and if we find that
1255 // we've already reported an error involving any particular
1256 // node we just stop and don't report the current error. The
1257 // idea is to report errors that derive from independent
1258 // regions of the graph, but not those that derive from
1259 // overlapping locations.
1260 let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect();
1261
1262 let mut opt_graph = None;
1263
1264 for idx in 0..self.num_vars() as usize {
1265 match var_data[idx].value {
1266 Value(_) => {
1267 /* Inference successful */
1268 }
1269 NoValue => {
1270 /* Unconstrained inference: do not report an error
1271 until the value of this variable is requested.
1272 After all, sometimes we make region variables but never
1273 really use their values. */
1274 }
1275 ErrorValue => {
1276 /* Inference impossible, this value contains
1277 inconsistent constraints.
1278
1279 I think that in this case we should report an
1280 error now---unlike the case above, we can't
1281 wait to see whether the user needs the result
1282 of this variable. The reason is that the mere
1283 existence of this variable implies that the
1284 region graph is inconsistent, whether or not it
1285 is used.
1286
1287 For example, we may have created a region
1288 variable that is the GLB of two other regions
1289 which do not have a GLB. Even if that variable
1290 is not used, it implies that those two regions
1291 *should* have a GLB.
1292
1293 At least I think this is true. It may be that
1294 the mere existence of a conflict in a region variable
1295 that is not used is not a problem, so if this rule
1296 starts to create problems we'll have to revisit
1297 this portion of the code and think hard about it. =) */
1298
1299 if opt_graph.is_none() {
1300 opt_graph = Some(self.construct_graph());
1301 }
1302 let graph = opt_graph.as_ref().unwrap();
1303
1304 let node_vid = RegionVid { index: idx as u32 };
1305 match var_data[idx].classification {
1306 Expanding => {
1307 self.collect_error_for_expanding_node(
1308 graph, var_data, &mut dup_vec,
1309 node_vid, errors);
1310 }
1311 Contracting => {
1312 self.collect_error_for_contracting_node(
1313 graph, var_data, &mut dup_vec,
1314 node_vid, errors);
1315 }
1316 }
1317 }
1318 }
1319 }
1320
1321 (0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect()
1322 }
1323
1324 fn construct_graph(&self) -> RegionGraph {
1325 let num_vars = self.num_vars();
1326
1327 let constraints = self.constraints.borrow();
1328 let num_edges = constraints.len();
1329
1330 let mut graph = graph::Graph::with_capacity(num_vars as usize + 1,
1331 num_edges);
1332
1333 for _ in 0..num_vars {
1334 graph.add_node(());
1335 }
1336 let dummy_idx = graph.add_node(());
1337
1338 for (constraint, _) in &*constraints {
1339 match *constraint {
1340 ConstrainVarSubVar(a_id, b_id) => {
1341 graph.add_edge(NodeIndex(a_id.index as usize),
1342 NodeIndex(b_id.index as usize),
1343 *constraint);
1344 }
1345 ConstrainRegSubVar(_, b_id) => {
1346 graph.add_edge(dummy_idx,
1347 NodeIndex(b_id.index as usize),
1348 *constraint);
1349 }
1350 ConstrainVarSubReg(a_id, _) => {
1351 graph.add_edge(NodeIndex(a_id.index as usize),
1352 dummy_idx,
1353 *constraint);
1354 }
1355 }
1356 }
1357
1358 return graph;
1359 }
1360
1361 fn collect_error_for_expanding_node(
1362 &self,
1363 graph: &RegionGraph,
1364 var_data: &[VarData],
1365 dup_vec: &mut [u32],
1366 node_idx: RegionVid,
1367 errors: &mut Vec<RegionResolutionError<'tcx>>)
1368 {
1369 // Errors in expanding nodes result from a lower-bound that is
1370 // not contained by an upper-bound.
1371 let (mut lower_bounds, lower_dup) =
1372 self.collect_concrete_regions(graph, var_data, node_idx,
1373 graph::Incoming, dup_vec);
1374 let (mut upper_bounds, upper_dup) =
1375 self.collect_concrete_regions(graph, var_data, node_idx,
1376 graph::Outgoing, dup_vec);
1377
1378 if lower_dup || upper_dup {
1379 return;
1380 }
1381
1382 // We place free regions first because we are special casing
1383 // SubSupConflict(ReFree, ReFree) when reporting error, and so
1384 // the user will more likely get a specific suggestion.
1385 fn free_regions_first(a: &RegionAndOrigin,
1386 b: &RegionAndOrigin)
1387 -> Ordering {
1388 match (a.region, b.region) {
1389 (ReFree(..), ReFree(..)) => Equal,
1390 (ReFree(..), _) => Less,
1391 (_, ReFree(..)) => Greater,
1392 (_, _) => Equal,
1393 }
1394 }
1395 lower_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1396 upper_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1397
1398 for lower_bound in &lower_bounds {
1399 for upper_bound in &upper_bounds {
1400 if !self.is_subregion_of(lower_bound.region,
1401 upper_bound.region) {
1402 debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
1403 lower_bound.region, upper_bound.region);
1404 errors.push(SubSupConflict(
1405 (*self.var_origins.borrow())[node_idx.index as usize].clone(),
1406 lower_bound.origin.clone(),
1407 lower_bound.region,
1408 upper_bound.origin.clone(),
1409 upper_bound.region));
1410 return;
1411 }
1412 }
1413 }
1414
1415 self.tcx.sess.span_bug(
1416 (*self.var_origins.borrow())[node_idx.index as usize].span(),
1417 &format!("collect_error_for_expanding_node() could not find error \
1418 for var {:?}, lower_bounds={}, upper_bounds={}",
1419 node_idx,
1420 lower_bounds.repr(self.tcx),
1421 upper_bounds.repr(self.tcx)));
1422 }
1423
1424 fn collect_error_for_contracting_node(
1425 &self,
1426 graph: &RegionGraph,
1427 var_data: &[VarData],
1428 dup_vec: &mut [u32],
1429 node_idx: RegionVid,
1430 errors: &mut Vec<RegionResolutionError<'tcx>>)
1431 {
1432 // Errors in contracting nodes result from two upper-bounds
1433 // that have no intersection.
1434 let (upper_bounds, dup_found) =
1435 self.collect_concrete_regions(graph, var_data, node_idx,
1436 graph::Outgoing, dup_vec);
1437
1438 if dup_found {
1439 return;
1440 }
1441
1442 for upper_bound_1 in &upper_bounds {
1443 for upper_bound_2 in &upper_bounds {
1444 match self.glb_concrete_regions(upper_bound_1.region,
1445 upper_bound_2.region) {
1446 Ok(_) => {}
1447 Err(_) => {
1448 errors.push(SupSupConflict(
1449 (*self.var_origins.borrow())[node_idx.index as usize].clone(),
1450 upper_bound_1.origin.clone(),
1451 upper_bound_1.region,
1452 upper_bound_2.origin.clone(),
1453 upper_bound_2.region));
1454 return;
1455 }
1456 }
1457 }
1458 }
1459
1460 self.tcx.sess.span_bug(
1461 (*self.var_origins.borrow())[node_idx.index as usize].span(),
1462 &format!("collect_error_for_contracting_node() could not find error \
1463 for var {:?}, upper_bounds={}",
1464 node_idx,
1465 upper_bounds.repr(self.tcx)));
1466 }
1467
1468 fn collect_concrete_regions(&self,
1469 graph: &RegionGraph,
1470 var_data: &[VarData],
1471 orig_node_idx: RegionVid,
1472 dir: Direction,
1473 dup_vec: &mut [u32])
1474 -> (Vec<RegionAndOrigin<'tcx>>, bool) {
1475 struct WalkState<'tcx> {
1476 set: FnvHashSet<RegionVid>,
1477 stack: Vec<RegionVid>,
1478 result: Vec<RegionAndOrigin<'tcx>>,
1479 dup_found: bool
1480 }
1481 let mut state = WalkState {
1482 set: FnvHashSet(),
1483 stack: vec!(orig_node_idx),
1484 result: Vec::new(),
1485 dup_found: false
1486 };
1487 state.set.insert(orig_node_idx);
1488
1489 // to start off the process, walk the source node in the
1490 // direction specified
1491 process_edges(self, &mut state, graph, orig_node_idx, dir);
1492
1493 while !state.stack.is_empty() {
1494 let node_idx = state.stack.pop().unwrap();
1495 let classification = var_data[node_idx.index as usize].classification;
1496
1497 // check whether we've visited this node on some previous walk
1498 if dup_vec[node_idx.index as usize] == u32::MAX {
1499 dup_vec[node_idx.index as usize] = orig_node_idx.index;
1500 } else if dup_vec[node_idx.index as usize] != orig_node_idx.index {
1501 state.dup_found = true;
1502 }
1503
1504 debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
1505 classification={:?})",
1506 orig_node_idx, node_idx, classification);
1507
1508 // figure out the direction from which this node takes its
1509 // values, and search for concrete regions etc in that direction
1510 let dir = match classification {
1511 Expanding => graph::Incoming,
1512 Contracting => graph::Outgoing,
1513 };
1514
1515 process_edges(self, &mut state, graph, node_idx, dir);
1516 }
1517
1518 let WalkState {result, dup_found, ..} = state;
1519 return (result, dup_found);
1520
1521 fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
1522 state: &mut WalkState<'tcx>,
1523 graph: &RegionGraph,
1524 source_vid: RegionVid,
1525 dir: Direction) {
1526 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
1527
1528 let source_node_index = NodeIndex(source_vid.index as usize);
1529 graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
1530 match edge.data {
1531 ConstrainVarSubVar(from_vid, to_vid) => {
1532 let opp_vid =
1533 if from_vid == source_vid {to_vid} else {from_vid};
1534 if state.set.insert(opp_vid) {
1535 state.stack.push(opp_vid);
1536 }
1537 }
1538
1539 ConstrainRegSubVar(region, _) |
1540 ConstrainVarSubReg(_, region) => {
1541 state.result.push(RegionAndOrigin {
1542 region: region,
1543 origin: this.constraints.borrow().get(&edge.data).unwrap().clone()
1544 });
1545 }
1546 }
1547 true
1548 });
1549 }
1550 }
1551
1552 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F) where
1553 F: FnMut(&Constraint) -> bool,
1554 {
1555 let mut iteration = 0;
1556 let mut changed = true;
1557 while changed {
1558 changed = false;
1559 iteration += 1;
1560 debug!("---- {} Iteration {}{}", "#", tag, iteration);
1561 for (constraint, _) in &*self.constraints.borrow() {
1562 let edge_changed = body(constraint);
1563 if edge_changed {
1564 debug!("Updated due to constraint {}",
1565 constraint.repr(self.tcx));
1566 changed = true;
1567 }
1568 }
1569 }
1570 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
1571 }
1572
1573 }
1574
1575 impl<'tcx> Repr<'tcx> for Constraint {
1576 fn repr(&self, tcx: &ty::ctxt) -> String {
1577 match *self {
1578 ConstrainVarSubVar(a, b) => {
1579 format!("ConstrainVarSubVar({}, {})", a.repr(tcx), b.repr(tcx))
1580 }
1581 ConstrainRegSubVar(a, b) => {
1582 format!("ConstrainRegSubVar({}, {})", a.repr(tcx), b.repr(tcx))
1583 }
1584 ConstrainVarSubReg(a, b) => {
1585 format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
1586 }
1587 }
1588 }
1589 }
1590
1591 impl<'tcx> Repr<'tcx> for Verify<'tcx> {
1592 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
1593 match *self {
1594 VerifyRegSubReg(_, ref a, ref b) => {
1595 format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
1596 }
1597 VerifyGenericBound(_, ref p, ref a, ref bs) => {
1598 format!("VerifyGenericBound({}, {}, {})",
1599 p.repr(tcx), a.repr(tcx), bs.repr(tcx))
1600 }
1601 }
1602 }
1603 }
1604
1605 fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
1606 match r {
1607 ty::ReInfer(ReVar(rid)) => lookup(values, rid),
1608 _ => r
1609 }
1610 }
1611
1612 fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
1613 match values[rid.index as usize] {
1614 Value(r) => r,
1615 NoValue => ReEmpty, // No constraints, return ty::ReEmpty
1616 ErrorValue => ReStatic, // Previously reported error.
1617 }
1618 }
1619
1620 impl<'tcx> Repr<'tcx> for VarValue {
1621 fn repr(&self, tcx: &ty::ctxt) -> String {
1622 match *self {
1623 NoValue => format!("NoValue"),
1624 Value(r) => format!("Value({})", r.repr(tcx)),
1625 ErrorValue => format!("ErrorValue"),
1626 }
1627 }
1628 }
1629
1630 impl<'tcx> Repr<'tcx> for RegionAndOrigin<'tcx> {
1631 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
1632 format!("RegionAndOrigin({},{})",
1633 self.region.repr(tcx),
1634 self.origin.repr(tcx))
1635 }
1636 }
1637
1638 impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
1639 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
1640 match *self {
1641 GenericKind::Param(ref p) => p.repr(tcx),
1642 GenericKind::Projection(ref p) => p.repr(tcx),
1643 }
1644 }
1645 }
1646
1647 impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
1648 fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
1649 match *self {
1650 GenericKind::Param(ref p) => p.user_string(tcx),
1651 GenericKind::Projection(ref p) => p.user_string(tcx),
1652 }
1653 }
1654 }
1655
1656 impl<'tcx> GenericKind<'tcx> {
1657 pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
1658 match *self {
1659 GenericKind::Param(ref p) =>
1660 p.to_ty(tcx),
1661 GenericKind::Projection(ref p) =>
1662 ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name),
1663 }
1664 }
1665 }