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