]> git.proxmox.com Git - rustc.git/blob - src/librustc/middle/infer/region_inference/mod.rs
f79fb6b625292cad22efdbcabeac6e21f83dcb3c
[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 rustc_data_structures::graph::{self, Direction, NodeIndex};
24 use middle::free_region::FreeRegionMap;
25 use middle::region;
26 use middle::ty::{self, Ty};
27 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
28 use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
29 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
30 use middle::ty_relate::RelateResult;
31 use util::common::indenter;
32 use util::nodemap::{FnvHashMap, FnvHashSet};
33
34 use std::cell::{Cell, RefCell};
35 use std::cmp::Ordering::{self, Less, Greater, Equal};
36 use std::fmt;
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, 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);
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);
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);
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,
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,
457 sup,
458 origin);
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,
476 sup));
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,
515 b);
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,
540 b);
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);
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);
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,
716 free_regions: &FreeRegionMap,
717 subject_node: ast::NodeId)
718 -> Vec<RegionResolutionError<'tcx>>
719 {
720 debug!("RegionVarBindings: resolve_regions()");
721 let mut errors = vec!();
722 let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
723 *self.values.borrow_mut() = Some(v);
724 errors
725 }
726
727 fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, 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,
736 b));
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(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 free_regions: &FreeRegionMap,
801 a: &FreeRegion,
802 b: &FreeRegion)
803 -> ty::Region
804 {
805 return match a.cmp(b) {
806 Less => helper(self, free_regions, a, b),
807 Greater => helper(self, free_regions, b, a),
808 Equal => ty::ReFree(*a)
809 };
810
811 fn helper(_this: &RegionVarBindings,
812 free_regions: &FreeRegionMap,
813 a: &FreeRegion,
814 b: &FreeRegion) -> ty::Region
815 {
816 if free_regions.sub_free_region(*a, *b) {
817 ty::ReFree(*b)
818 } else if free_regions.sub_free_region(*b, *a) {
819 ty::ReFree(*a)
820 } else {
821 ty::ReStatic
822 }
823 }
824 }
825
826 fn glb_concrete_regions(&self,
827 free_regions: &FreeRegionMap,
828 a: Region,
829 b: Region)
830 -> RelateResult<'tcx, Region>
831 {
832 debug!("glb_concrete_regions({:?}, {:?})", a, b);
833 match (a, b) {
834 (ReLateBound(..), _) |
835 (_, ReLateBound(..)) |
836 (ReEarlyBound(..), _) |
837 (_, ReEarlyBound(..)) => {
838 self.tcx.sess.bug(
839 &format!("cannot relate bound region: GLB({:?}, {:?})",
840 a,
841 b));
842 }
843
844 (ReStatic, r) | (r, ReStatic) => {
845 // static lives longer than everything else
846 Ok(r)
847 }
848
849 (ReEmpty, _) | (_, ReEmpty) => {
850 // nothing lives shorter than everything else
851 Ok(ReEmpty)
852 }
853
854 (ReInfer(ReVar(v_id)), _) |
855 (_, ReInfer(ReVar(v_id))) => {
856 self.tcx.sess.span_bug(
857 (*self.var_origins.borrow())[v_id.index as usize].span(),
858 &format!("glb_concrete_regions invoked with \
859 non-concrete regions: {:?}, {:?}",
860 a,
861 b));
862 }
863
864 (ReFree(ref fr), ReScope(s_id)) |
865 (ReScope(s_id), ReFree(ref fr)) => {
866 let s = ReScope(s_id);
867 // Free region is something "at least as big as
868 // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
869 // than the scope `s_id`, then we can say that the GLB
870 // is the scope `s_id`. Otherwise, as we do not know
871 // big the free region is precisely, the GLB is undefined.
872 let fr_scope = fr.scope.to_code_extent();
873 if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope {
874 Ok(s)
875 } else {
876 Err(ty::terr_regions_no_overlap(b, a))
877 }
878 }
879
880 (ReScope(a_id), ReScope(b_id)) => {
881 self.intersect_scopes(a, b, a_id, b_id)
882 }
883
884 (ReFree(ref a_fr), ReFree(ref b_fr)) => {
885 self.glb_free_regions(free_regions, a_fr, b_fr)
886 }
887
888 // For these types, we cannot define any additional
889 // relationship:
890 (ReInfer(ReSkolemized(..)), _) |
891 (_, ReInfer(ReSkolemized(..))) => {
892 if a == b {
893 Ok(a)
894 } else {
895 Err(ty::terr_regions_no_overlap(b, a))
896 }
897 }
898 }
899 }
900
901 /// Computes a region that is enclosed by both free region arguments, if any. Guarantees that
902 /// if the same two regions are given as argument, in any order, a consistent result is
903 /// returned.
904 fn glb_free_regions(&self,
905 free_regions: &FreeRegionMap,
906 a: &FreeRegion,
907 b: &FreeRegion)
908 -> RelateResult<'tcx, ty::Region>
909 {
910 return match a.cmp(b) {
911 Less => helper(self, free_regions, a, b),
912 Greater => helper(self, free_regions, b, a),
913 Equal => Ok(ty::ReFree(*a))
914 };
915
916 fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
917 free_regions: &FreeRegionMap,
918 a: &FreeRegion,
919 b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
920 {
921 if free_regions.sub_free_region(*a, *b) {
922 Ok(ty::ReFree(*a))
923 } else if free_regions.sub_free_region(*b, *a) {
924 Ok(ty::ReFree(*b))
925 } else {
926 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
927 a.scope.to_code_extent(),
928 b.scope.to_code_extent())
929 }
930 }
931 }
932
933 fn intersect_scopes(&self,
934 region_a: ty::Region,
935 region_b: ty::Region,
936 scope_a: region::CodeExtent,
937 scope_b: region::CodeExtent)
938 -> RelateResult<'tcx, Region>
939 {
940 // We want to generate the intersection of two
941 // scopes or two free regions. So, if one of
942 // these scopes is a subscope of the other, return
943 // it. Otherwise fail.
944 debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
945 scope_a, scope_b, region_a, region_b);
946 let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
947 if r_id == scope_a {
948 Ok(ReScope(scope_b))
949 } else if r_id == scope_b {
950 Ok(ReScope(scope_a))
951 } else {
952 Err(ty::terr_regions_no_overlap(region_a, region_b))
953 }
954 }
955 }
956
957 // ______________________________________________________________________
958
959 #[derive(Copy, Clone, PartialEq, Debug)]
960 enum Classification { Expanding, Contracting }
961
962 #[derive(Copy, Clone, Debug)]
963 pub enum VarValue { NoValue, Value(Region), ErrorValue }
964
965 struct VarData {
966 classification: Classification,
967 value: VarValue,
968 }
969
970 struct RegionAndOrigin<'tcx> {
971 region: Region,
972 origin: SubregionOrigin<'tcx>,
973 }
974
975 type RegionGraph = graph::Graph<(), Constraint>;
976
977 impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
978 fn infer_variable_values(&self,
979 free_regions: &FreeRegionMap,
980 errors: &mut Vec<RegionResolutionError<'tcx>>,
981 subject: ast::NodeId) -> Vec<VarValue>
982 {
983 let mut var_data = self.construct_var_data();
984
985 // Dorky hack to cause `dump_constraints` to only get called
986 // if debug mode is enabled:
987 debug!("----() End constraint listing (subject={}) {:?}---",
988 subject, self.dump_constraints(subject));
989 graphviz::maybe_print_constraints_for(self, subject);
990
991 let graph = self.construct_graph();
992 self.expand_givens(&graph);
993 self.expansion(free_regions, &mut var_data);
994 self.contraction(free_regions, &mut var_data);
995 let values =
996 self.extract_values_and_collect_conflicts(free_regions,
997 &var_data,
998 &graph,
999 errors);
1000 self.collect_concrete_region_errors(free_regions, &values, errors);
1001 values
1002 }
1003
1004 fn construct_var_data(&self) -> Vec<VarData> {
1005 (0..self.num_vars() as usize).map(|_| {
1006 VarData {
1007 // All nodes are initially classified as contracting; during
1008 // the expansion phase, we will shift the classification for
1009 // those nodes that have a concrete region predecessor to
1010 // Expanding.
1011 classification: Contracting,
1012 value: NoValue,
1013 }
1014 }).collect()
1015 }
1016
1017 fn dump_constraints(&self, subject: ast::NodeId) {
1018 debug!("----() Start constraint listing (subject={}) ()----", subject);
1019 for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
1020 debug!("Constraint {} => {:?}", idx, constraint);
1021 }
1022 }
1023
1024 fn expand_givens(&self, graph: &RegionGraph) {
1025 // Givens are a kind of horrible hack to account for
1026 // constraints like 'c <= '0 that are known to hold due to
1027 // closure signatures (see the comment above on the `givens`
1028 // field). They should go away. But until they do, the role
1029 // of this fn is to account for the transitive nature:
1030 //
1031 // Given 'c <= '0
1032 // and '0 <= '1
1033 // then 'c <= '1
1034
1035 let mut givens = self.givens.borrow_mut();
1036 let seeds: Vec<_> = givens.iter().cloned().collect();
1037 for (fr, vid) in seeds {
1038 let seed_index = NodeIndex(vid.index as usize);
1039 for succ_index in graph.depth_traverse(seed_index) {
1040 let succ_index = succ_index.0 as u32;
1041 if succ_index < self.num_vars() {
1042 let succ_vid = RegionVid { index: succ_index };
1043 givens.insert((fr, succ_vid));
1044 }
1045 }
1046 }
1047 }
1048
1049 fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
1050 self.iterate_until_fixed_point("Expansion", |constraint| {
1051 debug!("expansion: constraint={:?} origin={:?}",
1052 constraint,
1053 self.constraints.borrow()
1054 .get(constraint)
1055 .unwrap()
1056 );
1057 match *constraint {
1058 ConstrainRegSubVar(a_region, b_vid) => {
1059 let b_data = &mut var_data[b_vid.index as usize];
1060 self.expand_node(free_regions, a_region, b_vid, b_data)
1061 }
1062 ConstrainVarSubVar(a_vid, b_vid) => {
1063 match var_data[a_vid.index as usize].value {
1064 NoValue | ErrorValue => false,
1065 Value(a_region) => {
1066 let b_node = &mut var_data[b_vid.index as usize];
1067 self.expand_node(free_regions, a_region, b_vid, b_node)
1068 }
1069 }
1070 }
1071 ConstrainVarSubReg(..) => {
1072 // This is a contraction constraint. Ignore it.
1073 false
1074 }
1075 }
1076 })
1077 }
1078
1079 fn expand_node(&self,
1080 free_regions: &FreeRegionMap,
1081 a_region: Region,
1082 b_vid: RegionVid,
1083 b_data: &mut VarData)
1084 -> bool
1085 {
1086 debug!("expand_node({:?}, {:?} == {:?})",
1087 a_region,
1088 b_vid,
1089 b_data.value);
1090
1091 // Check if this relationship is implied by a given.
1092 match a_region {
1093 ty::ReFree(fr) => {
1094 if self.givens.borrow().contains(&(fr, b_vid)) {
1095 debug!("given");
1096 return false;
1097 }
1098 }
1099 _ => { }
1100 }
1101
1102 b_data.classification = Expanding;
1103 match b_data.value {
1104 NoValue => {
1105 debug!("Setting initial value of {:?} to {:?}",
1106 b_vid, a_region);
1107
1108 b_data.value = Value(a_region);
1109 return true;
1110 }
1111
1112 Value(cur_region) => {
1113 let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
1114 if lub == cur_region {
1115 return false;
1116 }
1117
1118 debug!("Expanding value of {:?} from {:?} to {:?}",
1119 b_vid,
1120 cur_region,
1121 lub);
1122
1123 b_data.value = Value(lub);
1124 return true;
1125 }
1126
1127 ErrorValue => {
1128 return false;
1129 }
1130 }
1131 }
1132
1133 fn contraction(&self,
1134 free_regions: &FreeRegionMap,
1135 var_data: &mut [VarData]) {
1136 self.iterate_until_fixed_point("Contraction", |constraint| {
1137 debug!("contraction: constraint={:?} origin={:?}",
1138 constraint,
1139 self.constraints.borrow()
1140 .get(constraint)
1141 .unwrap()
1142 );
1143 match *constraint {
1144 ConstrainRegSubVar(..) => {
1145 // This is an expansion constraint. Ignore.
1146 false
1147 }
1148 ConstrainVarSubVar(a_vid, b_vid) => {
1149 match var_data[b_vid.index as usize].value {
1150 NoValue | ErrorValue => false,
1151 Value(b_region) => {
1152 let a_data = &mut var_data[a_vid.index as usize];
1153 self.contract_node(free_regions, a_vid, a_data, b_region)
1154 }
1155 }
1156 }
1157 ConstrainVarSubReg(a_vid, b_region) => {
1158 let a_data = &mut var_data[a_vid.index as usize];
1159 self.contract_node(free_regions, a_vid, a_data, b_region)
1160 }
1161 }
1162 })
1163 }
1164
1165 fn contract_node(&self,
1166 free_regions: &FreeRegionMap,
1167 a_vid: RegionVid,
1168 a_data: &mut VarData,
1169 b_region: Region)
1170 -> bool {
1171 debug!("contract_node({:?} == {:?}/{:?}, {:?})",
1172 a_vid, a_data.value,
1173 a_data.classification, b_region);
1174
1175 return match a_data.value {
1176 NoValue => {
1177 assert_eq!(a_data.classification, Contracting);
1178 a_data.value = Value(b_region);
1179 true // changed
1180 }
1181
1182 ErrorValue => false, // no change
1183
1184 Value(a_region) => {
1185 match a_data.classification {
1186 Expanding =>
1187 check_node(self, free_regions, a_vid, a_data, a_region, b_region),
1188 Contracting =>
1189 adjust_node(self, free_regions, a_vid, a_data, a_region, b_region),
1190 }
1191 }
1192 };
1193
1194 fn check_node(this: &RegionVarBindings,
1195 free_regions: &FreeRegionMap,
1196 a_vid: RegionVid,
1197 a_data: &mut VarData,
1198 a_region: Region,
1199 b_region: Region)
1200 -> bool
1201 {
1202 if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
1203 debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
1204 a_vid,
1205 a_region,
1206 b_region);
1207 a_data.value = ErrorValue;
1208 }
1209 false
1210 }
1211
1212 fn adjust_node(this: &RegionVarBindings,
1213 free_regions: &FreeRegionMap,
1214 a_vid: RegionVid,
1215 a_data: &mut VarData,
1216 a_region: Region,
1217 b_region: Region)
1218 -> bool {
1219 match this.glb_concrete_regions(free_regions, a_region, b_region) {
1220 Ok(glb) => {
1221 if glb == a_region {
1222 false
1223 } else {
1224 debug!("Contracting value of {:?} from {:?} to {:?}",
1225 a_vid,
1226 a_region,
1227 glb);
1228 a_data.value = Value(glb);
1229 true
1230 }
1231 }
1232 Err(_) => {
1233 debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
1234 a_vid,
1235 a_region,
1236 b_region);
1237 a_data.value = ErrorValue;
1238 false
1239 }
1240 }
1241 }
1242 }
1243
1244 fn collect_concrete_region_errors(&self,
1245 free_regions: &FreeRegionMap,
1246 values: &Vec<VarValue>,
1247 errors: &mut Vec<RegionResolutionError<'tcx>>)
1248 {
1249 let mut reg_reg_dups = FnvHashSet();
1250 for verify in self.verifys.borrow().iter() {
1251 match *verify {
1252 VerifyRegSubReg(ref origin, sub, sup) => {
1253 if free_regions.is_subregion_of(self.tcx, sub, sup) {
1254 continue;
1255 }
1256
1257 if !reg_reg_dups.insert((sub, sup)) {
1258 continue;
1259 }
1260
1261 debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
1262 sub,
1263 sup);
1264 errors.push(ConcreteFailure((*origin).clone(), sub, sup));
1265 }
1266
1267 VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
1268 let sub = normalize(values, sub);
1269 if sups.iter()
1270 .map(|&sup| normalize(values, sup))
1271 .any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup))
1272 {
1273 continue;
1274 }
1275
1276 let sups = sups.iter().map(|&sup| normalize(values, sup))
1277 .collect();
1278 errors.push(
1279 GenericBoundFailure(
1280 (*origin).clone(), kind.clone(), sub, sups));
1281 }
1282 }
1283 }
1284 }
1285
1286 fn extract_values_and_collect_conflicts(
1287 &self,
1288 free_regions: &FreeRegionMap,
1289 var_data: &[VarData],
1290 graph: &RegionGraph,
1291 errors: &mut Vec<RegionResolutionError<'tcx>>)
1292 -> Vec<VarValue>
1293 {
1294 debug!("extract_values_and_collect_conflicts()");
1295
1296 // This is the best way that I have found to suppress
1297 // duplicate and related errors. Basically we keep a set of
1298 // flags for every node. Whenever an error occurs, we will
1299 // walk some portion of the graph looking to find pairs of
1300 // conflicting regions to report to the user. As we walk, we
1301 // trip the flags from false to true, and if we find that
1302 // we've already reported an error involving any particular
1303 // node we just stop and don't report the current error. The
1304 // idea is to report errors that derive from independent
1305 // regions of the graph, but not those that derive from
1306 // overlapping locations.
1307 let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect();
1308
1309 for idx in 0..self.num_vars() as usize {
1310 match var_data[idx].value {
1311 Value(_) => {
1312 /* Inference successful */
1313 }
1314 NoValue => {
1315 /* Unconstrained inference: do not report an error
1316 until the value of this variable is requested.
1317 After all, sometimes we make region variables but never
1318 really use their values. */
1319 }
1320 ErrorValue => {
1321 /* Inference impossible, this value contains
1322 inconsistent constraints.
1323
1324 I think that in this case we should report an
1325 error now---unlike the case above, we can't
1326 wait to see whether the user needs the result
1327 of this variable. The reason is that the mere
1328 existence of this variable implies that the
1329 region graph is inconsistent, whether or not it
1330 is used.
1331
1332 For example, we may have created a region
1333 variable that is the GLB of two other regions
1334 which do not have a GLB. Even if that variable
1335 is not used, it implies that those two regions
1336 *should* have a GLB.
1337
1338 At least I think this is true. It may be that
1339 the mere existence of a conflict in a region variable
1340 that is not used is not a problem, so if this rule
1341 starts to create problems we'll have to revisit
1342 this portion of the code and think hard about it. =) */
1343
1344 let node_vid = RegionVid { index: idx as u32 };
1345 match var_data[idx].classification {
1346 Expanding => {
1347 self.collect_error_for_expanding_node(
1348 free_regions, graph, var_data, &mut dup_vec,
1349 node_vid, errors);
1350 }
1351 Contracting => {
1352 self.collect_error_for_contracting_node(
1353 free_regions, graph, var_data, &mut dup_vec,
1354 node_vid, errors);
1355 }
1356 }
1357 }
1358 }
1359 }
1360
1361 // Check for future hostile edges tied to a bad default
1362 self.report_future_hostility(&graph);
1363
1364 (0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect()
1365 }
1366
1367 fn report_future_hostility(&self, graph: &RegionGraph) {
1368 let constraints = self.constraints.borrow();
1369 for edge in graph.all_edges() {
1370 match constraints[&edge.data] {
1371 SubregionOrigin::DefaultExistentialBound(_) => {
1372 // this will become 'static in the future
1373 }
1374 _ => { continue; }
1375 }
1376
1377 // this constraint will become a 'static constraint in the
1378 // future, so walk outward and see if we have any hard
1379 // bounds that could not be inferred to 'static
1380 for nid in graph.depth_traverse(edge.target()) {
1381 for (_, succ) in graph.outgoing_edges(nid) {
1382 match succ.data {
1383 ConstrainVarSubReg(_, r) => {
1384 match r {
1385 ty::ReStatic | ty::ReInfer(_) => {
1386 /* OK */
1387 }
1388 ty::ReFree(_) | ty::ReScope(_) | ty::ReEmpty => {
1389 span_warn!(
1390 self.tcx.sess,
1391 constraints[&edge.data].span(),
1392 E0398,
1393 "this code may fail to compile in Rust 1.3 due to \
1394 the proposed change in object lifetime bound defaults");
1395 return; // only issue the warning once per fn
1396 }
1397 ty::ReEarlyBound(..) | ty::ReLateBound(..) => {
1398 self.tcx.sess.span_bug(
1399 constraints[&succ.data].span(),
1400 "relation to bound region");
1401 }
1402 }
1403 }
1404 _ => { }
1405 }
1406 }
1407 }
1408 }
1409 }
1410
1411 fn construct_graph(&self) -> RegionGraph {
1412 let num_vars = self.num_vars();
1413
1414 let constraints = self.constraints.borrow();
1415
1416 let mut graph = graph::Graph::new();
1417
1418 for _ in 0..num_vars {
1419 graph.add_node(());
1420 }
1421 let dummy_idx = graph.add_node(());
1422
1423 for (constraint, _) in constraints.iter() {
1424 match *constraint {
1425 ConstrainVarSubVar(a_id, b_id) => {
1426 graph.add_edge(NodeIndex(a_id.index as usize),
1427 NodeIndex(b_id.index as usize),
1428 *constraint);
1429 }
1430 ConstrainRegSubVar(_, b_id) => {
1431 graph.add_edge(dummy_idx,
1432 NodeIndex(b_id.index as usize),
1433 *constraint);
1434 }
1435 ConstrainVarSubReg(a_id, _) => {
1436 graph.add_edge(NodeIndex(a_id.index as usize),
1437 dummy_idx,
1438 *constraint);
1439 }
1440 }
1441 }
1442
1443 return graph;
1444 }
1445
1446 fn collect_error_for_expanding_node(&self,
1447 free_regions: &FreeRegionMap,
1448 graph: &RegionGraph,
1449 var_data: &[VarData],
1450 dup_vec: &mut [u32],
1451 node_idx: RegionVid,
1452 errors: &mut Vec<RegionResolutionError<'tcx>>)
1453 {
1454 // Errors in expanding nodes result from a lower-bound that is
1455 // not contained by an upper-bound.
1456 let (mut lower_bounds, lower_dup) =
1457 self.collect_concrete_regions(graph, var_data, node_idx,
1458 graph::INCOMING, dup_vec);
1459 let (mut upper_bounds, upper_dup) =
1460 self.collect_concrete_regions(graph, var_data, node_idx,
1461 graph::OUTGOING, dup_vec);
1462
1463 if lower_dup || upper_dup {
1464 return;
1465 }
1466
1467 // We place free regions first because we are special casing
1468 // SubSupConflict(ReFree, ReFree) when reporting error, and so
1469 // the user will more likely get a specific suggestion.
1470 fn free_regions_first(a: &RegionAndOrigin,
1471 b: &RegionAndOrigin)
1472 -> Ordering {
1473 match (a.region, b.region) {
1474 (ReFree(..), ReFree(..)) => Equal,
1475 (ReFree(..), _) => Less,
1476 (_, ReFree(..)) => Greater,
1477 (_, _) => Equal,
1478 }
1479 }
1480 lower_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1481 upper_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1482
1483 for lower_bound in &lower_bounds {
1484 for upper_bound in &upper_bounds {
1485 if !free_regions.is_subregion_of(self.tcx,
1486 lower_bound.region,
1487 upper_bound.region) {
1488 debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
1489 lower_bound.region, upper_bound.region);
1490 errors.push(SubSupConflict(
1491 (*self.var_origins.borrow())[node_idx.index as usize].clone(),
1492 lower_bound.origin.clone(),
1493 lower_bound.region,
1494 upper_bound.origin.clone(),
1495 upper_bound.region));
1496 return;
1497 }
1498 }
1499 }
1500
1501 self.tcx.sess.span_bug(
1502 (*self.var_origins.borrow())[node_idx.index as usize].span(),
1503 &format!("collect_error_for_expanding_node() could not find error \
1504 for var {:?}, lower_bounds={:?}, upper_bounds={:?}",
1505 node_idx,
1506 lower_bounds,
1507 upper_bounds));
1508 }
1509
1510 fn collect_error_for_contracting_node(
1511 &self,
1512 free_regions: &FreeRegionMap,
1513 graph: &RegionGraph,
1514 var_data: &[VarData],
1515 dup_vec: &mut [u32],
1516 node_idx: RegionVid,
1517 errors: &mut Vec<RegionResolutionError<'tcx>>)
1518 {
1519 // Errors in contracting nodes result from two upper-bounds
1520 // that have no intersection.
1521 let (upper_bounds, dup_found) =
1522 self.collect_concrete_regions(graph, var_data, node_idx,
1523 graph::OUTGOING, dup_vec);
1524
1525 if dup_found {
1526 return;
1527 }
1528
1529 for upper_bound_1 in &upper_bounds {
1530 for upper_bound_2 in &upper_bounds {
1531 match self.glb_concrete_regions(free_regions,
1532 upper_bound_1.region,
1533 upper_bound_2.region) {
1534 Ok(_) => {}
1535 Err(_) => {
1536 errors.push(SupSupConflict(
1537 (*self.var_origins.borrow())[node_idx.index as usize].clone(),
1538 upper_bound_1.origin.clone(),
1539 upper_bound_1.region,
1540 upper_bound_2.origin.clone(),
1541 upper_bound_2.region));
1542 return;
1543 }
1544 }
1545 }
1546 }
1547
1548 self.tcx.sess.span_bug(
1549 (*self.var_origins.borrow())[node_idx.index as usize].span(),
1550 &format!("collect_error_for_contracting_node() could not find error \
1551 for var {:?}, upper_bounds={:?}",
1552 node_idx,
1553 upper_bounds));
1554 }
1555
1556 fn collect_concrete_regions(&self,
1557 graph: &RegionGraph,
1558 var_data: &[VarData],
1559 orig_node_idx: RegionVid,
1560 dir: Direction,
1561 dup_vec: &mut [u32])
1562 -> (Vec<RegionAndOrigin<'tcx>>, bool) {
1563 struct WalkState<'tcx> {
1564 set: FnvHashSet<RegionVid>,
1565 stack: Vec<RegionVid>,
1566 result: Vec<RegionAndOrigin<'tcx>>,
1567 dup_found: bool
1568 }
1569 let mut state = WalkState {
1570 set: FnvHashSet(),
1571 stack: vec!(orig_node_idx),
1572 result: Vec::new(),
1573 dup_found: false
1574 };
1575 state.set.insert(orig_node_idx);
1576
1577 // to start off the process, walk the source node in the
1578 // direction specified
1579 process_edges(self, &mut state, graph, orig_node_idx, dir);
1580
1581 while !state.stack.is_empty() {
1582 let node_idx = state.stack.pop().unwrap();
1583 let classification = var_data[node_idx.index as usize].classification;
1584
1585 // check whether we've visited this node on some previous walk
1586 if dup_vec[node_idx.index as usize] == u32::MAX {
1587 dup_vec[node_idx.index as usize] = orig_node_idx.index;
1588 } else if dup_vec[node_idx.index as usize] != orig_node_idx.index {
1589 state.dup_found = true;
1590 }
1591
1592 debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
1593 classification={:?})",
1594 orig_node_idx, node_idx, classification);
1595
1596 // figure out the direction from which this node takes its
1597 // values, and search for concrete regions etc in that direction
1598 let dir = match classification {
1599 Expanding => graph::INCOMING,
1600 Contracting => graph::OUTGOING,
1601 };
1602
1603 process_edges(self, &mut state, graph, node_idx, dir);
1604 }
1605
1606 let WalkState {result, dup_found, ..} = state;
1607 return (result, dup_found);
1608
1609 fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
1610 state: &mut WalkState<'tcx>,
1611 graph: &RegionGraph,
1612 source_vid: RegionVid,
1613 dir: Direction) {
1614 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
1615
1616 let source_node_index = NodeIndex(source_vid.index as usize);
1617 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
1618 match edge.data {
1619 ConstrainVarSubVar(from_vid, to_vid) => {
1620 let opp_vid =
1621 if from_vid == source_vid {to_vid} else {from_vid};
1622 if state.set.insert(opp_vid) {
1623 state.stack.push(opp_vid);
1624 }
1625 }
1626
1627 ConstrainRegSubVar(region, _) |
1628 ConstrainVarSubReg(_, region) => {
1629 state.result.push(RegionAndOrigin {
1630 region: region,
1631 origin: this.constraints.borrow().get(&edge.data).unwrap().clone()
1632 });
1633 }
1634 }
1635 }
1636 }
1637 }
1638
1639 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F) where
1640 F: FnMut(&Constraint) -> bool,
1641 {
1642 let mut iteration = 0;
1643 let mut changed = true;
1644 while changed {
1645 changed = false;
1646 iteration += 1;
1647 debug!("---- {} Iteration {}{}", "#", tag, iteration);
1648 for (constraint, _) in self.constraints.borrow().iter() {
1649 let edge_changed = body(constraint);
1650 if edge_changed {
1651 debug!("Updated due to constraint {:?}",
1652 constraint);
1653 changed = true;
1654 }
1655 }
1656 }
1657 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
1658 }
1659
1660 }
1661
1662 impl<'tcx> fmt::Debug for Verify<'tcx> {
1663 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1664 match *self {
1665 VerifyRegSubReg(_, ref a, ref b) => {
1666 write!(f, "VerifyRegSubReg({:?}, {:?})", a, b)
1667 }
1668 VerifyGenericBound(_, ref p, ref a, ref bs) => {
1669 write!(f, "VerifyGenericBound({:?}, {:?}, {:?})", p, a, bs)
1670 }
1671 }
1672 }
1673 }
1674
1675 fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
1676 match r {
1677 ty::ReInfer(ReVar(rid)) => lookup(values, rid),
1678 _ => r
1679 }
1680 }
1681
1682 fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
1683 match values[rid.index as usize] {
1684 Value(r) => r,
1685 NoValue => ReEmpty, // No constraints, return ty::ReEmpty
1686 ErrorValue => ReStatic, // Previously reported error.
1687 }
1688 }
1689
1690 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
1691 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1692 write!(f, "RegionAndOrigin({:?},{:?})",
1693 self.region,
1694 self.origin)
1695 }
1696 }
1697
1698 impl<'tcx> fmt::Debug for GenericKind<'tcx> {
1699 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1700 match *self {
1701 GenericKind::Param(ref p) => write!(f, "{:?}", p),
1702 GenericKind::Projection(ref p) => write!(f, "{:?}", p),
1703 }
1704 }
1705 }
1706
1707 impl<'tcx> fmt::Display for GenericKind<'tcx> {
1708 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1709 match *self {
1710 GenericKind::Param(ref p) => write!(f, "{}", p),
1711 GenericKind::Projection(ref p) => write!(f, "{}", p),
1712 }
1713 }
1714 }
1715
1716 impl<'tcx> GenericKind<'tcx> {
1717 pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
1718 match *self {
1719 GenericKind::Param(ref p) =>
1720 p.to_ty(tcx),
1721 GenericKind::Projection(ref p) =>
1722 ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name),
1723 }
1724 }
1725 }