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.
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.
13 pub use self::Constraint::*;
14 pub use self::UndoLogEntry::*;
15 pub use self::CombineMapType::*;
16 pub use self::RegionResolutionError::*;
17 pub use self::VarValue::*;
19 use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable};
22 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
23 use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING};
24 use rustc_data_structures::unify::{self, UnificationTable};
25 use middle::free_region::FreeRegionMap;
26 use ty::{self, Ty, TyCtxt};
27 use ty::{Region, RegionVid};
28 use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased};
29 use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
31 use std::cell::{Cell, RefCell};
32 use std::cmp::Ordering::{self, Less, Greater, Equal};
40 // A constraint that influences the inference process.
41 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
42 pub enum Constraint<'tcx> {
43 // One region variable is subregion of another
44 ConstrainVarSubVar(RegionVid, RegionVid),
46 // Concrete region is subregion of region variable
47 ConstrainRegSubVar(Region<'tcx>, RegionVid),
49 // Region variable is subregion of concrete region. This does not
50 // directly affect inference, but instead is checked after
51 // inference is complete.
52 ConstrainVarSubReg(RegionVid, Region<'tcx>),
54 // A constraint where neither side is a variable. This does not
55 // directly affect inference, but instead is checked after
56 // inference is complete.
57 ConstrainRegSubReg(Region<'tcx>, Region<'tcx>),
60 // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
61 // associated type) must outlive the region `R`. `T` is known to
62 // outlive `RS`. Therefore verify that `R <= RS[i]` for some
63 // `i`. Inference variables may be involved (but this verification
64 // step doesn't influence inference).
66 pub struct Verify<'tcx> {
67 kind: GenericKind<'tcx>,
68 origin: SubregionOrigin<'tcx>,
70 bound: VerifyBound<'tcx>,
73 #[derive(Copy, Clone, PartialEq, Eq)]
74 pub enum GenericKind<'tcx> {
76 Projection(ty::ProjectionTy<'tcx>),
79 // When we introduce a verification step, we wish to test that a
80 // particular region (let's call it `'min`) meets some bound.
81 // The bound is described the by the following grammar:
83 pub enum VerifyBound<'tcx> {
84 // B = exists {R} --> some 'r in {R} must outlive 'min
86 // Put another way, the subject value is known to outlive all
87 // regions in {R}, so if any of those outlives 'min, then the
89 AnyRegion(Vec<Region<'tcx>>),
91 // B = forall {R} --> all 'r in {R} must outlive 'min
93 // Put another way, the subject value is known to outlive some
94 // region in {R}, so if all of those outlives 'min, then the bound
96 AllRegions(Vec<Region<'tcx>>),
98 // B = exists {B} --> 'min must meet some bound b in {B}
99 AnyBound(Vec<VerifyBound<'tcx>>),
101 // B = forall {B} --> 'min must meet all bounds b in {B}
102 AllBounds(Vec<VerifyBound<'tcx>>),
105 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
106 pub struct TwoRegions<'tcx> {
111 #[derive(Copy, Clone, PartialEq)]
112 pub enum UndoLogEntry<'tcx> {
113 /// Pushed when we start a snapshot.
116 /// Replaces an `OpenSnapshot` when a snapshot is committed, but
117 /// that snapshot is not the root. If the root snapshot is
118 /// unrolled, all nested snapshots must be committed.
121 /// We added `RegionVid`
124 /// We added the given `constraint`
125 AddConstraint(Constraint<'tcx>),
127 /// We added the given `verify`
130 /// We added the given `given`
131 AddGiven(ty::FreeRegion<'tcx>, ty::RegionVid),
133 /// We added a GLB/LUB "combinaton variable"
134 AddCombination(CombineMapType, TwoRegions<'tcx>),
136 /// During skolemization, we sometimes purge entries from the undo
137 /// log in a kind of minisnapshot (unlike other snapshots, this
138 /// purging actually takes place *on success*). In that case, we
139 /// replace the corresponding entry with `Noop` so as to avoid the
140 /// need to do a bunch of swapping. (We can't use `swap_remove` as
141 /// the order of the vector is important.)
145 #[derive(Copy, Clone, PartialEq)]
146 pub enum CombineMapType {
151 #[derive(Clone, Debug)]
152 pub enum RegionResolutionError<'tcx> {
153 /// `ConcreteFailure(o, a, b)`:
155 /// `o` requires that `a <= b`, but this does not hold
156 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
158 /// `GenericBoundFailure(p, s, a)
160 /// The parameter/associated-type `p` must be known to outlive the lifetime
161 /// `a` (but none of the known bounds are sufficient).
162 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
164 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
166 /// Could not infer a value for `v` because `sub_r <= v` (due to
167 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
168 /// `sub_r <= sup_r` does not hold.
169 SubSupConflict(RegionVariableOrigin,
170 SubregionOrigin<'tcx>,
172 SubregionOrigin<'tcx>,
176 #[derive(Clone, Debug)]
177 pub enum ProcessedErrorOrigin<'tcx> {
178 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
179 VariableFailure(RegionVariableOrigin),
182 pub type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
184 pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
185 tcx: TyCtxt<'a, 'gcx, 'tcx>,
186 var_origins: RefCell<Vec<RegionVariableOrigin>>,
188 // Constraints of the form `A <= B` introduced by the region
189 // checker. Here at least one of `A` and `B` must be a region
191 constraints: RefCell<FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>>,
193 // A "verify" is something that we need to verify after inference is
194 // done, but which does not directly affect inference in any way.
196 // An example is a `A <= B` where neither `A` nor `B` are
197 // inference variables.
198 verifys: RefCell<Vec<Verify<'tcx>>>,
200 // A "given" is a relationship that is known to hold. In particular,
201 // we often know from closure fn signatures that a particular free
202 // region must be a subregion of a region variable:
204 // foo.iter().filter(<'a> |x: &'a &'b T| ...)
206 // In situations like this, `'b` is in fact a region variable
207 // introduced by the call to `iter()`, and `'a` is a bound region
208 // on the closure (as indicated by the `<'a>` prefix). If we are
209 // naive, we wind up inferring that `'b` must be `'static`,
210 // because we require that it be greater than `'a` and we do not
211 // know what `'a` is precisely.
213 // This hashmap is used to avoid that naive scenario. Basically we
214 // record the fact that `'a <= 'b` is implied by the fn signature,
215 // and then ignore the constraint when solving equations. This is
216 // a bit of a hack but seems to work.
217 givens: RefCell<FxHashSet<(ty::FreeRegion<'tcx>, ty::RegionVid)>>,
219 lubs: RefCell<CombineMap<'tcx>>,
220 glbs: RefCell<CombineMap<'tcx>>,
221 skolemization_count: Cell<u32>,
222 bound_count: Cell<u32>,
224 // The undo log records actions that might later be undone.
226 // Note: when the undo_log is empty, we are not actively
227 // snapshotting. When the `start_snapshot()` method is called, we
228 // push an OpenSnapshot entry onto the list to indicate that we
229 // are now actively snapshotting. The reason for this is that
230 // otherwise we end up adding entries for things like the lower
231 // bound on a variable and so forth, which can never be rolled
233 undo_log: RefCell<Vec<UndoLogEntry<'tcx>>>,
234 unification_table: RefCell<UnificationTable<ty::RegionVid>>,
236 // This contains the results of inference. It begins as an empty
237 // option and only acquires a value after inference is complete.
238 values: RefCell<Option<Vec<VarValue<'tcx>>>>,
241 pub struct RegionSnapshot {
243 region_snapshot: unify::Snapshot<ty::RegionVid>,
244 skolemization_count: u32,
247 /// When working with skolemized regions, we often wish to find all of
248 /// the regions that are either reachable from a skolemized region, or
249 /// which can reach a skolemized region, or both. We call such regions
250 /// *tained* regions. This struct allows you to decide what set of
251 /// tainted regions you want.
253 pub struct TaintDirections {
258 impl TaintDirections {
259 pub fn incoming() -> Self {
260 TaintDirections { incoming: true, outgoing: false }
263 pub fn outgoing() -> Self {
264 TaintDirections { incoming: false, outgoing: true }
267 pub fn both() -> Self {
268 TaintDirections { incoming: true, outgoing: true }
272 struct TaintSet<'tcx> {
273 directions: TaintDirections,
274 regions: FxHashSet<ty::Region<'tcx>>
277 impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
278 fn new(directions: TaintDirections,
279 initial_region: ty::Region<'tcx>)
281 let mut regions = FxHashSet();
282 regions.insert(initial_region);
283 TaintSet { directions: directions, regions: regions }
286 fn fixed_point(&mut self,
287 tcx: TyCtxt<'a, 'gcx, 'tcx>,
288 undo_log: &[UndoLogEntry<'tcx>],
289 verifys: &[Verify<'tcx>]) {
290 let mut prev_len = 0;
291 while prev_len < self.len() {
292 debug!("tainted: prev_len = {:?} new_len = {:?}",
293 prev_len, self.len());
295 prev_len = self.len();
297 for undo_entry in undo_log {
299 &AddConstraint(ConstrainVarSubVar(a, b)) => {
300 self.add_edge(tcx.mk_region(ReVar(a)),
301 tcx.mk_region(ReVar(b)));
303 &AddConstraint(ConstrainRegSubVar(a, b)) => {
304 self.add_edge(a, tcx.mk_region(ReVar(b)));
306 &AddConstraint(ConstrainVarSubReg(a, b)) => {
307 self.add_edge(tcx.mk_region(ReVar(a)), b);
309 &AddConstraint(ConstrainRegSubReg(a, b)) => {
313 self.add_edge(tcx.mk_region(ReFree(a)),
314 tcx.mk_region(ReVar(b)));
317 verifys[i].bound.for_each_region(&mut |b| {
318 self.add_edge(verifys[i].region, b);
322 &AddCombination(..) |
325 &CommitedSnapshot => {}
331 fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
335 fn len(&self) -> usize {
339 fn add_edge(&mut self,
340 source: ty::Region<'tcx>,
341 target: ty::Region<'tcx>) {
342 if self.directions.incoming {
343 if self.regions.contains(&target) {
344 self.regions.insert(source);
348 if self.directions.outgoing {
349 if self.regions.contains(&source) {
350 self.regions.insert(target);
356 impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
357 pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> RegionVarBindings<'a, 'gcx, 'tcx> {
360 var_origins: RefCell::new(Vec::new()),
361 values: RefCell::new(None),
362 constraints: RefCell::new(FxHashMap()),
363 verifys: RefCell::new(Vec::new()),
364 givens: RefCell::new(FxHashSet()),
365 lubs: RefCell::new(FxHashMap()),
366 glbs: RefCell::new(FxHashMap()),
367 skolemization_count: Cell::new(0),
368 bound_count: Cell::new(0),
369 undo_log: RefCell::new(Vec::new()),
370 unification_table: RefCell::new(UnificationTable::new()),
374 fn in_snapshot(&self) -> bool {
375 !self.undo_log.borrow().is_empty()
378 pub fn start_snapshot(&self) -> RegionSnapshot {
379 let length = self.undo_log.borrow().len();
380 debug!("RegionVarBindings: start_snapshot({})", length);
381 self.undo_log.borrow_mut().push(OpenSnapshot);
384 region_snapshot: self.unification_table.borrow_mut().snapshot(),
385 skolemization_count: self.skolemization_count.get(),
389 pub fn commit(&self, snapshot: RegionSnapshot) {
390 debug!("RegionVarBindings: commit({})", snapshot.length);
391 assert!(self.undo_log.borrow().len() > snapshot.length);
392 assert!((*self.undo_log.borrow())[snapshot.length] == OpenSnapshot);
393 assert!(self.skolemization_count.get() == snapshot.skolemization_count,
394 "failed to pop skolemized regions: {} now vs {} at start",
395 self.skolemization_count.get(),
396 snapshot.skolemization_count);
398 let mut undo_log = self.undo_log.borrow_mut();
399 if snapshot.length == 0 {
400 undo_log.truncate(0);
402 (*undo_log)[snapshot.length] = CommitedSnapshot;
404 self.unification_table.borrow_mut().commit(snapshot.region_snapshot);
407 pub fn rollback_to(&self, snapshot: RegionSnapshot) {
408 debug!("RegionVarBindings: rollback_to({:?})", snapshot);
409 let mut undo_log = self.undo_log.borrow_mut();
410 assert!(undo_log.len() > snapshot.length);
411 assert!((*undo_log)[snapshot.length] == OpenSnapshot);
412 while undo_log.len() > snapshot.length + 1 {
413 self.rollback_undo_entry(undo_log.pop().unwrap());
415 let c = undo_log.pop().unwrap();
416 assert!(c == OpenSnapshot);
417 self.skolemization_count.set(snapshot.skolemization_count);
418 self.unification_table.borrow_mut()
419 .rollback_to(snapshot.region_snapshot);
422 pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) {
425 panic!("Failure to observe stack discipline");
427 Purged | CommitedSnapshot => {
428 // nothing to do here
431 let mut var_origins = self.var_origins.borrow_mut();
432 var_origins.pop().unwrap();
433 assert_eq!(var_origins.len(), vid.index as usize);
435 AddConstraint(ref constraint) => {
436 self.constraints.borrow_mut().remove(constraint);
438 AddVerify(index) => {
439 self.verifys.borrow_mut().pop();
440 assert_eq!(self.verifys.borrow().len(), index);
442 AddGiven(sub, sup) => {
443 self.givens.borrow_mut().remove(&(sub, sup));
445 AddCombination(Glb, ref regions) => {
446 self.glbs.borrow_mut().remove(regions);
448 AddCombination(Lub, ref regions) => {
449 self.lubs.borrow_mut().remove(regions);
454 pub fn num_vars(&self) -> u32 {
455 let len = self.var_origins.borrow().len();
456 // enforce no overflow
457 assert!(len as u32 as usize == len);
461 pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
462 let vid = RegionVid { index: self.num_vars() };
463 self.var_origins.borrow_mut().push(origin.clone());
465 let u_vid = self.unification_table.borrow_mut().new_key(
466 unify_key::RegionVidKey { min_vid: vid }
468 assert_eq!(vid, u_vid);
469 if self.in_snapshot() {
470 self.undo_log.borrow_mut().push(AddVar(vid));
472 debug!("created new region variable {:?} with origin {:?}",
478 pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
479 self.var_origins.borrow()[vid.index as usize].clone()
482 /// Creates a new skolemized region. Skolemized regions are fresh
483 /// regions used when performing higher-ranked computations. They
484 /// must be used in a very particular way and are never supposed
485 /// to "escape" out into error messages or the code at large.
487 /// The idea is to always create a snapshot. Skolemized regions
488 /// can be created in the context of this snapshot, but before the
489 /// snapshot is committed or rolled back, they must be popped
490 /// (using `pop_skolemized_regions`), so that their numbers can be
491 /// recycled. Normally you don't have to think about this: you use
492 /// the APIs in `higher_ranked/mod.rs`, such as
493 /// `skolemize_late_bound_regions` and `plug_leaks`, which will
494 /// guide you on this path (ensure that the `SkolemizationMap` is
495 /// consumed and you are good). There are also somewhat extensive
496 /// comments in `higher_ranked/README.md`.
498 /// The `snapshot` argument to this function is not really used;
499 /// it's just there to make it explicit which snapshot bounds the
500 /// skolemized region that results. It should always be the top-most snapshot.
501 pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot)
503 assert!(self.in_snapshot());
504 assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
506 let sc = self.skolemization_count.get();
507 self.skolemization_count.set(sc + 1);
508 self.tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br))
511 /// Removes all the edges to/from the skolemized regions that are
512 /// in `skols`. This is used after a higher-ranked operation
513 /// completes to remove all trace of the skolemized regions
514 /// created in that time.
515 pub fn pop_skolemized(&self,
516 skols: &FxHashSet<ty::Region<'tcx>>,
517 snapshot: &RegionSnapshot) {
518 debug!("pop_skolemized_regions(skols={:?})", skols);
520 assert!(self.in_snapshot());
521 assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
522 assert!(self.skolemization_count.get() as usize >= skols.len(),
523 "popping more skolemized variables than actually exist, \
524 sc now = {}, skols.len = {}",
525 self.skolemization_count.get(),
528 let last_to_pop = self.skolemization_count.get();
529 let first_to_pop = last_to_pop - (skols.len() as u32);
531 assert!(first_to_pop >= snapshot.skolemization_count,
532 "popping more regions than snapshot contains, \
533 sc now = {}, sc then = {}, skols.len = {}",
534 self.skolemization_count.get(),
535 snapshot.skolemization_count,
540 ty::ReSkolemized(index, _) =>
541 index.index >= first_to_pop &&
542 index.index < last_to_pop,
546 "invalid skolemization keys or keys out of range ({}..{}): {:?}",
547 snapshot.skolemization_count,
548 self.skolemization_count.get(),
552 let mut undo_log = self.undo_log.borrow_mut();
554 let constraints_to_kill: Vec<usize> =
558 .filter(|&(_, undo_entry)| kill_constraint(skols, undo_entry))
559 .map(|(index, _)| index)
562 for index in constraints_to_kill {
563 let undo_entry = mem::replace(&mut undo_log[index], Purged);
564 self.rollback_undo_entry(undo_entry);
567 self.skolemization_count.set(snapshot.skolemization_count);
570 fn kill_constraint<'tcx>(skols: &FxHashSet<ty::Region<'tcx>>,
571 undo_entry: &UndoLogEntry<'tcx>)
574 &AddConstraint(ConstrainVarSubVar(..)) =>
576 &AddConstraint(ConstrainRegSubVar(a, _)) =>
578 &AddConstraint(ConstrainVarSubReg(_, b)) =>
580 &AddConstraint(ConstrainRegSubReg(a, b)) =>
581 skols.contains(&a) || skols.contains(&b),
586 &AddCombination(_, ref two_regions) =>
587 skols.contains(&two_regions.a) ||
588 skols.contains(&two_regions.b),
599 pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region<'tcx> {
600 // Creates a fresh bound variable for use in GLB computations.
601 // See discussion of GLB computation in the large comment at
602 // the top of this file for more details.
604 // This computation is potentially wrong in the face of
605 // rollover. It's conceivable, if unlikely, that one might
606 // wind up with accidental capture for nested functions in
607 // that case, if the outer function had bound regions created
608 // a very long time before and the inner function somehow
609 // wound up rolling over such that supposedly fresh
610 // identifiers were in fact shadowed. For now, we just assert
611 // that there is no rollover -- eventually we should try to be
612 // robust against this possibility, either by checking the set
613 // of bound identifiers that appear in a given expression and
614 // ensure that we generate one that is distinct, or by
615 // changing the representation of bound regions in a fn
618 let sc = self.bound_count.get();
619 self.bound_count.set(sc + 1);
621 if sc >= self.bound_count.get() {
622 bug!("rollover in RegionInference new_bound()");
625 self.tcx.mk_region(ReLateBound(debruijn, BrFresh(sc)))
628 fn values_are_none(&self) -> bool {
629 self.values.borrow().is_none()
632 fn add_constraint(&self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
633 // cannot add constraints once regions are resolved
634 assert!(self.values_are_none());
636 debug!("RegionVarBindings: add_constraint({:?})", constraint);
638 if self.constraints.borrow_mut().insert(constraint, origin).is_none() {
639 if self.in_snapshot() {
640 self.undo_log.borrow_mut().push(AddConstraint(constraint));
645 fn add_verify(&self, verify: Verify<'tcx>) {
646 // cannot add verifys once regions are resolved
647 assert!(self.values_are_none());
649 debug!("RegionVarBindings: add_verify({:?})", verify);
651 // skip no-op cases known to be satisfied
653 VerifyBound::AllBounds(ref bs) if bs.len() == 0 => { return; }
657 let mut verifys = self.verifys.borrow_mut();
658 let index = verifys.len();
659 verifys.push(verify);
660 if self.in_snapshot() {
661 self.undo_log.borrow_mut().push(AddVerify(index));
665 pub fn add_given(&self, sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) {
666 // cannot add givens once regions are resolved
667 assert!(self.values_are_none());
669 let mut givens = self.givens.borrow_mut();
670 if givens.insert((sub, sup)) {
671 debug!("add_given({:?} <= {:?})", sub, sup);
673 self.undo_log.borrow_mut().push(AddGiven(sub, sup));
677 pub fn make_eqregion(&self,
678 origin: SubregionOrigin<'tcx>,
682 // Eventually, it would be nice to add direct support for
684 self.make_subregion(origin.clone(), sub, sup);
685 self.make_subregion(origin, sup, sub);
687 if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
688 self.unification_table.borrow_mut().union(sub, sup);
693 pub fn make_subregion(&self,
694 origin: SubregionOrigin<'tcx>,
697 // cannot add constraints once regions are resolved
698 assert!(self.values_are_none());
700 debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}",
706 (&ReEarlyBound(..), _) |
707 (&ReLateBound(..), _) |
708 (_, &ReEarlyBound(..)) |
709 (_, &ReLateBound(..)) => {
710 span_bug!(origin.span(),
711 "cannot relate bound region: {:?} <= {:?}",
716 // all regions are subregions of static, so we can ignore this
718 (&ReVar(sub_id), &ReVar(sup_id)) => {
719 self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
721 (_, &ReVar(sup_id)) => {
722 self.add_constraint(ConstrainRegSubVar(sub, sup_id), origin);
724 (&ReVar(sub_id), _) => {
725 self.add_constraint(ConstrainVarSubReg(sub_id, sup), origin);
728 self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
733 /// See `Verify::VerifyGenericBound`
734 pub fn verify_generic_bound(&self,
735 origin: SubregionOrigin<'tcx>,
736 kind: GenericKind<'tcx>,
738 bound: VerifyBound<'tcx>) {
739 self.add_verify(Verify {
747 pub fn lub_regions(&self,
748 origin: SubregionOrigin<'tcx>,
752 // cannot add constraints once regions are resolved
753 assert!(self.values_are_none());
755 debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
757 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
758 r // nothing lives longer than static
766 self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| {
767 this.make_subregion(origin.clone(), old_r, new_r)
773 pub fn glb_regions(&self,
774 origin: SubregionOrigin<'tcx>,
778 // cannot add constraints once regions are resolved
779 assert!(self.values_are_none());
781 debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
783 (&ReStatic, r) | (r, &ReStatic) => {
784 r // static lives longer than everything else
792 self.combine_vars(Glb, a, b, origin.clone(), |this, old_r, new_r| {
793 this.make_subregion(origin.clone(), new_r, old_r)
799 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
800 match *self.values.borrow() {
802 span_bug!((*self.var_origins.borrow())[rid.index as usize].span(),
803 "attempt to resolve region variable before values have \
806 Some(ref values) => {
807 let r = lookup(self.tcx, values, rid);
808 debug!("resolve_var({:?}) = {:?}", rid, r);
814 pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
815 let vid = self.unification_table.borrow_mut().find_value(rid).min_vid;
816 self.tcx.mk_region(ty::ReVar(vid))
819 fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap<'tcx>> {
826 pub fn combine_vars<F>(&self,
830 origin: SubregionOrigin<'tcx>,
833 where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region<'tcx>, Region<'tcx>)
835 let vars = TwoRegions { a: a, b: b };
836 if let Some(&c) = self.combine_map(t).borrow().get(&vars) {
837 return self.tcx.mk_region(ReVar(c));
839 let c = self.new_region_var(MiscVariable(origin.span()));
840 self.combine_map(t).borrow_mut().insert(vars, c);
841 if self.in_snapshot() {
842 self.undo_log.borrow_mut().push(AddCombination(t, vars));
844 relate(self, a, self.tcx.mk_region(ReVar(c)));
845 relate(self, b, self.tcx.mk_region(ReVar(c)));
846 debug!("combine_vars() c={:?}", c);
847 self.tcx.mk_region(ReVar(c))
850 pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> {
851 self.undo_log.borrow()[mark.length..]
855 AddVar(vid) => Some(vid),
862 /// Computes all regions that have been related to `r0` since the
863 /// mark `mark` was made---`r0` itself will be the first
864 /// entry. The `directions` parameter controls what kind of
865 /// relations are considered. For example, one can say that only
866 /// "incoming" edges to `r0` are desired, in which case one will
867 /// get the set of regions `{r|r <= r0}`. This is used when
868 /// checking whether skolemized regions are being improperly
869 /// related to other regions.
870 pub fn tainted(&self,
871 mark: &RegionSnapshot,
873 directions: TaintDirections)
874 -> FxHashSet<ty::Region<'tcx>> {
875 debug!("tainted(mark={:?}, r0={:?}, directions={:?})",
876 mark, r0, directions);
878 // `result_set` acts as a worklist: we explore all outgoing
879 // edges and add any new regions we find to result_set. This
880 // is not a terribly efficient implementation.
881 let mut taint_set = TaintSet::new(directions, r0);
882 taint_set.fixed_point(self.tcx,
883 &self.undo_log.borrow()[mark.length..],
884 &self.verifys.borrow());
885 debug!("tainted: result={:?}", taint_set.regions);
886 return taint_set.into_set();
889 /// This function performs the actual region resolution. It must be
890 /// called after all constraints have been added. It performs a
891 /// fixed-point iteration to find region values which satisfy all
892 /// constraints, assuming such values can be found; if they cannot,
893 /// errors are reported.
894 pub fn resolve_regions(&self,
895 free_regions: &FreeRegionMap<'tcx>,
896 subject_node: ast::NodeId)
897 -> Vec<RegionResolutionError<'tcx>> {
898 debug!("RegionVarBindings: resolve_regions()");
899 let mut errors = vec![];
900 let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
901 *self.values.borrow_mut() = Some(v);
905 fn lub_concrete_regions(&self,
906 free_regions: &FreeRegionMap<'tcx>,
911 (&ReLateBound(..), _) |
912 (_, &ReLateBound(..)) |
913 (&ReEarlyBound(..), _) |
914 (_, &ReEarlyBound(..)) |
917 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
920 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
921 r // nothing lives longer than static
924 (&ReEmpty, r) | (r, &ReEmpty) => {
925 r // everything lives longer than empty
928 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
929 span_bug!((*self.var_origins.borrow())[v_id.index as usize].span(),
930 "lub_concrete_regions invoked with non-concrete \
931 regions: {:?}, {:?}",
936 (&ReFree(fr), &ReScope(s_id)) |
937 (&ReScope(s_id), &ReFree(fr)) => {
938 // A "free" region can be interpreted as "some region
939 // at least as big as the block fr.scope_id". So, we can
940 // reasonably compare free regions and scopes:
941 if let Some(fr_scope) = fr.scope {
942 let r_id = self.tcx.region_maps().nearest_common_ancestor(fr_scope, s_id);
943 if r_id == fr_scope {
944 // if the free region's scope `fr.scope_id` is bigger than
945 // the scope region `s_id`, then the LUB is the free
947 return self.tcx.mk_region(ReFree(fr));
951 // otherwise, we don't know what the free region is,
952 // so we must conservatively say the LUB is static:
953 self.tcx.types.re_static
956 (&ReScope(a_id), &ReScope(b_id)) => {
957 // The region corresponding to an outer block is a
958 // subtype of the region corresponding to an inner
960 self.tcx.mk_region(ReScope(
961 self.tcx.region_maps().nearest_common_ancestor(a_id, b_id)))
964 (&ReFree(_), &ReFree(_)) => {
965 free_regions.lub_free_regions(self.tcx, a, b)
968 // For these types, we cannot define any additional
970 (&ReSkolemized(..), _) |
971 (_, &ReSkolemized(..)) => {
975 self.tcx.types.re_static
982 // ______________________________________________________________________
984 #[derive(Copy, Clone, Debug)]
985 pub enum VarValue<'tcx> {
990 struct RegionAndOrigin<'tcx> {
991 region: Region<'tcx>,
992 origin: SubregionOrigin<'tcx>,
995 type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>;
997 impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
998 fn infer_variable_values(&self,
999 free_regions: &FreeRegionMap<'tcx>,
1000 errors: &mut Vec<RegionResolutionError<'tcx>>,
1001 subject: ast::NodeId)
1002 -> Vec<VarValue<'tcx>> {
1003 let mut var_data = self.construct_var_data();
1005 // Dorky hack to cause `dump_constraints` to only get called
1006 // if debug mode is enabled:
1007 debug!("----() End constraint listing (subject={}) {:?}---",
1009 self.dump_constraints(subject));
1010 graphviz::maybe_print_constraints_for(self, subject);
1012 let graph = self.construct_graph();
1013 self.expand_givens(&graph);
1014 self.expansion(free_regions, &mut var_data);
1015 self.collect_errors(free_regions, &mut var_data, errors);
1016 self.collect_var_errors(free_regions, &var_data, &graph, errors);
1020 fn construct_var_data(&self) -> Vec<VarValue<'tcx>> {
1021 (0..self.num_vars() as usize)
1022 .map(|_| Value(self.tcx.types.re_empty))
1026 fn dump_constraints(&self, subject: ast::NodeId) {
1027 debug!("----() Start constraint listing (subject={}) ()----",
1029 for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
1030 debug!("Constraint {} => {:?}", idx, constraint);
1034 fn expand_givens(&self, graph: &RegionGraph) {
1035 // Givens are a kind of horrible hack to account for
1036 // constraints like 'c <= '0 that are known to hold due to
1037 // closure signatures (see the comment above on the `givens`
1038 // field). They should go away. But until they do, the role
1039 // of this fn is to account for the transitive nature:
1045 let mut givens = self.givens.borrow_mut();
1046 let seeds: Vec<_> = givens.iter().cloned().collect();
1047 for (fr, vid) in seeds {
1048 let seed_index = NodeIndex(vid.index as usize);
1049 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
1050 let succ_index = succ_index.0 as u32;
1051 if succ_index < self.num_vars() {
1052 let succ_vid = RegionVid { index: succ_index };
1053 givens.insert((fr, succ_vid));
1059 fn expansion(&self, free_regions: &FreeRegionMap<'tcx>, var_values: &mut [VarValue<'tcx>]) {
1060 self.iterate_until_fixed_point("Expansion", |constraint, origin| {
1061 debug!("expansion: constraint={:?} origin={:?}",
1062 constraint, origin);
1064 ConstrainRegSubVar(a_region, b_vid) => {
1065 let b_data = &mut var_values[b_vid.index as usize];
1066 self.expand_node(free_regions, a_region, b_vid, b_data)
1068 ConstrainVarSubVar(a_vid, b_vid) => {
1069 match var_values[a_vid.index as usize] {
1070 ErrorValue => false,
1071 Value(a_region) => {
1072 let b_node = &mut var_values[b_vid.index as usize];
1073 self.expand_node(free_regions, a_region, b_vid, b_node)
1077 ConstrainRegSubReg(..) |
1078 ConstrainVarSubReg(..) => {
1079 // These constraints are checked after expansion
1080 // is done, in `collect_errors`.
1087 fn expand_node(&self,
1088 free_regions: &FreeRegionMap<'tcx>,
1089 a_region: Region<'tcx>,
1091 b_data: &mut VarValue<'tcx>)
1093 debug!("expand_node({:?}, {:?} == {:?})",
1098 // Check if this relationship is implied by a given.
1101 if self.givens.borrow().contains(&(fr, b_vid)) {
1110 Value(cur_region) => {
1111 let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
1112 if lub == cur_region {
1116 debug!("Expanding value of {:?} from {:?} to {:?}",
1121 *b_data = Value(lub);
1131 /// After expansion is complete, go and check upper bounds (i.e.,
1132 /// cases where the region cannot grow larger than a fixed point)
1133 /// and check that they are satisfied.
1134 fn collect_errors(&self,
1135 free_regions: &FreeRegionMap<'tcx>,
1136 var_data: &mut Vec<VarValue<'tcx>>,
1137 errors: &mut Vec<RegionResolutionError<'tcx>>) {
1138 let constraints = self.constraints.borrow();
1139 for (constraint, origin) in constraints.iter() {
1140 debug!("collect_errors: constraint={:?} origin={:?}",
1141 constraint, origin);
1143 ConstrainRegSubVar(..) |
1144 ConstrainVarSubVar(..) => {
1145 // Expansion will ensure that these constraints hold. Ignore.
1148 ConstrainRegSubReg(sub, sup) => {
1149 if free_regions.is_subregion_of(self.tcx, sub, sup) {
1153 debug!("collect_errors: region error at {:?}: \
1154 cannot verify that {:?} <= {:?}",
1159 errors.push(ConcreteFailure((*origin).clone(), sub, sup));
1162 ConstrainVarSubReg(a_vid, b_region) => {
1163 let a_data = &mut var_data[a_vid.index as usize];
1164 debug!("contraction: {:?} == {:?}, {:?}",
1169 let a_region = match *a_data {
1170 ErrorValue => continue,
1171 Value(a_region) => a_region,
1174 // Do not report these errors immediately:
1175 // instead, set the variable value to error and
1176 // collect them later.
1177 if !free_regions.is_subregion_of(self.tcx, a_region, b_region) {
1178 debug!("collect_errors: region error at {:?}: \
1179 cannot verify that {:?}={:?} <= {:?}",
1184 *a_data = ErrorValue;
1190 for verify in self.verifys.borrow().iter() {
1191 debug!("collect_errors: verify={:?}", verify);
1192 let sub = normalize(self.tcx, var_data, verify.region);
1193 if verify.bound.is_met(self.tcx, free_regions, var_data, sub) {
1197 debug!("collect_errors: region error at {:?}: \
1198 cannot verify that {:?} <= {:?}",
1203 errors.push(GenericBoundFailure(verify.origin.clone(),
1204 verify.kind.clone(),
1209 /// Go over the variables that were declared to be error variables
1210 /// and create a `RegionResolutionError` for each of them.
1211 fn collect_var_errors(&self,
1212 free_regions: &FreeRegionMap<'tcx>,
1213 var_data: &[VarValue<'tcx>],
1214 graph: &RegionGraph<'tcx>,
1215 errors: &mut Vec<RegionResolutionError<'tcx>>) {
1216 debug!("collect_var_errors");
1218 // This is the best way that I have found to suppress
1219 // duplicate and related errors. Basically we keep a set of
1220 // flags for every node. Whenever an error occurs, we will
1221 // walk some portion of the graph looking to find pairs of
1222 // conflicting regions to report to the user. As we walk, we
1223 // trip the flags from false to true, and if we find that
1224 // we've already reported an error involving any particular
1225 // node we just stop and don't report the current error. The
1226 // idea is to report errors that derive from independent
1227 // regions of the graph, but not those that derive from
1228 // overlapping locations.
1229 let mut dup_vec = vec![u32::MAX; self.num_vars() as usize];
1231 for idx in 0..self.num_vars() as usize {
1232 match var_data[idx] {
1234 /* Inference successful */
1237 /* Inference impossible, this value contains
1238 inconsistent constraints.
1240 I think that in this case we should report an
1241 error now---unlike the case above, we can't
1242 wait to see whether the user needs the result
1243 of this variable. The reason is that the mere
1244 existence of this variable implies that the
1245 region graph is inconsistent, whether or not it
1248 For example, we may have created a region
1249 variable that is the GLB of two other regions
1250 which do not have a GLB. Even if that variable
1251 is not used, it implies that those two regions
1252 *should* have a GLB.
1254 At least I think this is true. It may be that
1255 the mere existence of a conflict in a region variable
1256 that is not used is not a problem, so if this rule
1257 starts to create problems we'll have to revisit
1258 this portion of the code and think hard about it. =) */
1260 let node_vid = RegionVid { index: idx as u32 };
1261 self.collect_error_for_expanding_node(free_regions,
1271 fn construct_graph(&self) -> RegionGraph<'tcx> {
1272 let num_vars = self.num_vars();
1274 let constraints = self.constraints.borrow();
1276 let mut graph = graph::Graph::new();
1278 for _ in 0..num_vars {
1282 // Issue #30438: two distinct dummy nodes, one for incoming
1283 // edges (dummy_source) and another for outgoing edges
1284 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
1285 // dummy node leads one to think (erroneously) there exists a
1286 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
1287 let dummy_source = graph.add_node(());
1288 let dummy_sink = graph.add_node(());
1290 for (constraint, _) in constraints.iter() {
1292 ConstrainVarSubVar(a_id, b_id) => {
1293 graph.add_edge(NodeIndex(a_id.index as usize),
1294 NodeIndex(b_id.index as usize),
1297 ConstrainRegSubVar(_, b_id) => {
1298 graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint);
1300 ConstrainVarSubReg(a_id, _) => {
1301 graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint);
1303 ConstrainRegSubReg(..) => {
1304 // this would be an edge from `dummy_source` to
1305 // `dummy_sink`; just ignore it.
1313 fn collect_error_for_expanding_node(&self,
1314 free_regions: &FreeRegionMap<'tcx>,
1315 graph: &RegionGraph<'tcx>,
1316 dup_vec: &mut [u32],
1317 node_idx: RegionVid,
1318 errors: &mut Vec<RegionResolutionError<'tcx>>) {
1319 // Errors in expanding nodes result from a lower-bound that is
1320 // not contained by an upper-bound.
1321 let (mut lower_bounds, lower_dup) = self.collect_concrete_regions(graph,
1325 let (mut upper_bounds, upper_dup) = self.collect_concrete_regions(graph,
1330 if lower_dup || upper_dup {
1334 // We place free regions first because we are special casing
1335 // SubSupConflict(ReFree, ReFree) when reporting error, and so
1336 // the user will more likely get a specific suggestion.
1337 fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering {
1338 match (a.region, b.region) {
1339 (&ReFree(..), &ReFree(..)) => Equal,
1340 (&ReFree(..), _) => Less,
1341 (_, &ReFree(..)) => Greater,
1345 lower_bounds.sort_by(|a, b| free_regions_first(a, b));
1346 upper_bounds.sort_by(|a, b| free_regions_first(a, b));
1348 for lower_bound in &lower_bounds {
1349 for upper_bound in &upper_bounds {
1350 if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) {
1351 let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone();
1352 debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
1357 upper_bound.region);
1358 errors.push(SubSupConflict(origin,
1359 lower_bound.origin.clone(),
1361 upper_bound.origin.clone(),
1362 upper_bound.region));
1368 span_bug!((*self.var_origins.borrow())[node_idx.index as usize].span(),
1369 "collect_error_for_expanding_node() could not find \
1370 error for var {:?}, lower_bounds={:?}, \
1377 fn collect_concrete_regions(&self,
1378 graph: &RegionGraph<'tcx>,
1379 orig_node_idx: RegionVid,
1381 dup_vec: &mut [u32])
1382 -> (Vec<RegionAndOrigin<'tcx>>, bool) {
1383 struct WalkState<'tcx> {
1384 set: FxHashSet<RegionVid>,
1385 stack: Vec<RegionVid>,
1386 result: Vec<RegionAndOrigin<'tcx>>,
1389 let mut state = WalkState {
1391 stack: vec![orig_node_idx],
1395 state.set.insert(orig_node_idx);
1397 // to start off the process, walk the source node in the
1398 // direction specified
1399 process_edges(self, &mut state, graph, orig_node_idx, dir);
1401 while !state.stack.is_empty() {
1402 let node_idx = state.stack.pop().unwrap();
1404 // check whether we've visited this node on some previous walk
1405 if dup_vec[node_idx.index as usize] == u32::MAX {
1406 dup_vec[node_idx.index as usize] = orig_node_idx.index;
1407 } else if dup_vec[node_idx.index as usize] != orig_node_idx.index {
1408 state.dup_found = true;
1411 debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
1415 process_edges(self, &mut state, graph, node_idx, dir);
1418 let WalkState {result, dup_found, ..} = state;
1419 return (result, dup_found);
1421 fn process_edges<'a, 'gcx, 'tcx>(this: &RegionVarBindings<'a, 'gcx, 'tcx>,
1422 state: &mut WalkState<'tcx>,
1423 graph: &RegionGraph<'tcx>,
1424 source_vid: RegionVid,
1426 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
1428 let source_node_index = NodeIndex(source_vid.index as usize);
1429 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
1431 ConstrainVarSubVar(from_vid, to_vid) => {
1432 let opp_vid = if from_vid == source_vid {
1437 if state.set.insert(opp_vid) {
1438 state.stack.push(opp_vid);
1442 ConstrainRegSubVar(region, _) |
1443 ConstrainVarSubReg(_, region) => {
1444 state.result.push(RegionAndOrigin {
1446 origin: this.constraints.borrow().get(&edge.data).unwrap().clone(),
1450 ConstrainRegSubReg(..) => {
1451 panic!("cannot reach reg-sub-reg edge in region inference \
1459 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
1460 where F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool
1462 let mut iteration = 0;
1463 let mut changed = true;
1467 debug!("---- {} Iteration {}{}", "#", tag, iteration);
1468 for (constraint, origin) in self.constraints.borrow().iter() {
1469 let edge_changed = body(constraint, origin);
1471 debug!("Updated due to constraint {:?}", constraint);
1476 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
1481 fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
1482 values: &Vec<VarValue<'tcx>>,
1483 r: ty::Region<'tcx>)
1484 -> ty::Region<'tcx> {
1486 ty::ReVar(rid) => lookup(tcx, values, rid),
1491 fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
1492 values: &Vec<VarValue<'tcx>>,
1494 -> ty::Region<'tcx> {
1495 match values[rid.index as usize] {
1497 ErrorValue => tcx.types.re_static, // Previously reported error.
1501 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
1502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1503 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
1507 impl fmt::Debug for RegionSnapshot {
1508 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1509 write!(f, "RegionSnapshot(length={},skolemization={})",
1510 self.length, self.skolemization_count)
1514 impl<'tcx> fmt::Debug for GenericKind<'tcx> {
1515 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1517 GenericKind::Param(ref p) => write!(f, "{:?}", p),
1518 GenericKind::Projection(ref p) => write!(f, "{:?}", p),
1523 impl<'tcx> fmt::Display for GenericKind<'tcx> {
1524 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1526 GenericKind::Param(ref p) => write!(f, "{}", p),
1527 GenericKind::Projection(ref p) => write!(f, "{}", p),
1532 impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
1533 pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
1535 GenericKind::Param(ref p) => p.to_ty(tcx),
1536 GenericKind::Projection(ref p) => tcx.mk_projection(p.trait_ref.clone(), p.item_name),
1541 impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
1542 fn for_each_region(&self, f: &mut FnMut(ty::Region<'tcx>)) {
1544 &VerifyBound::AnyRegion(ref rs) |
1545 &VerifyBound::AllRegions(ref rs) => for &r in rs {
1549 &VerifyBound::AnyBound(ref bs) |
1550 &VerifyBound::AllBounds(ref bs) => for b in bs {
1551 b.for_each_region(f);
1556 pub fn must_hold(&self) -> bool {
1558 &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
1559 &VerifyBound::AllRegions(ref bs) => bs.is_empty(),
1560 &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
1561 &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
1565 pub fn cannot_hold(&self) -> bool {
1567 &VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
1568 &VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
1569 &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
1570 &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
1574 pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
1575 if self.must_hold() || vb.cannot_hold() {
1577 } else if self.cannot_hold() || vb.must_hold() {
1580 VerifyBound::AnyBound(vec![self, vb])
1584 pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
1585 if self.must_hold() && vb.must_hold() {
1587 } else if self.cannot_hold() && vb.cannot_hold() {
1590 VerifyBound::AllBounds(vec![self, vb])
1594 fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
1595 free_regions: &FreeRegionMap<'tcx>,
1596 var_values: &Vec<VarValue<'tcx>>,
1597 min: ty::Region<'tcx>)
1600 &VerifyBound::AnyRegion(ref rs) =>
1602 .map(|&r| normalize(tcx, var_values, r))
1603 .any(|r| free_regions.is_subregion_of(tcx, min, r)),
1605 &VerifyBound::AllRegions(ref rs) =>
1607 .map(|&r| normalize(tcx, var_values, r))
1608 .all(|r| free_regions.is_subregion_of(tcx, min, r)),
1610 &VerifyBound::AnyBound(ref bs) =>
1612 .any(|b| b.is_met(tcx, free_regions, var_values, min)),
1614 &VerifyBound::AllBounds(ref bs) =>
1616 .all(|b| b.is_met(tcx, free_regions, var_values, min)),