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::Verify
::*;
15 pub use self::UndoLogEntry
::*;
16 pub use self::CombineMapType
::*;
17 pub use self::RegionResolutionError
::*;
18 pub use self::VarValue
::*;
20 use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}
;
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}
;
34 use std
::cell
::{Cell, RefCell}
;
35 use std
::cmp
::Ordering
::{self, Less, Greater, Equal}
;
42 // A constraint that influences the inference process.
43 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
45 // One region variable is subregion of another
46 ConstrainVarSubVar(RegionVid
, RegionVid
),
48 // Concrete region is subregion of region variable
49 ConstrainRegSubVar(Region
, RegionVid
),
51 // Region variable is subregion of concrete region
53 // FIXME(#29436) -- should be remove in favor of a Verify
54 ConstrainVarSubReg(RegionVid
, Region
),
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
),
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
),
72 #[derive(Copy, Clone, PartialEq, Eq)]
73 pub enum GenericKind
<'tcx
> {
75 Projection(ty
::ProjectionTy
<'tcx
>),
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:
82 pub enum VerifyBound
{
83 // B = exists {R} --> some 'r in {R} must outlive 'min
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
88 AnyRegion(Vec
<Region
>),
90 // B = forall {R} --> all 'r in {R} must outlive 'min
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
95 AllRegions(Vec
<Region
>),
97 // B = exists {B} --> 'min must meet some bound b in {B}
98 AnyBound(Vec
<VerifyBound
>),
100 // B = forall {B} --> 'min must meet all bounds b in {B}
101 AllBounds(Vec
<VerifyBound
>),
104 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
105 pub struct TwoRegions
{
110 #[derive(Copy, Clone, PartialEq)]
111 pub enum UndoLogEntry
{
115 AddConstraint(Constraint
),
117 AddGiven(ty
::FreeRegion
, ty
::RegionVid
),
118 AddCombination(CombineMapType
, TwoRegions
),
121 #[derive(Copy, Clone, PartialEq)]
122 pub enum CombineMapType
{
127 #[derive(Clone, Debug)]
128 pub enum RegionResolutionError
<'tcx
> {
129 /// `ConcreteFailure(o, a, b)`:
131 /// `o` requires that `a <= b`, but this does not hold
132 ConcreteFailure(SubregionOrigin
<'tcx
>, Region
, Region
),
134 /// `GenericBoundFailure(p, s, a)
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
),
140 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
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
>,
148 SubregionOrigin
<'tcx
>,
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
>)>,
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
164 /// struct Foo { bar: i32 }
165 /// fn foo2<'a, 'b>(x: &'a Foo) -> &'b i32 {
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
>,
178 pub fn contains(&self, other
: &BoundRegion
) -> bool
{
179 self.regions
.contains(other
)
182 pub fn push(&mut self, other
: BoundRegion
) {
183 self.regions
.push(other
);
187 pub type CombineMap
= FnvHashMap
<TwoRegions
, RegionVid
>;
189 pub struct RegionVarBindings
<'a
, 'tcx
: 'a
> {
190 tcx
: &'a ty
::ctxt
<'tcx
>,
191 var_origins
: RefCell
<Vec
<RegionVariableOrigin
>>,
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
196 constraints
: RefCell
<FnvHashMap
<Constraint
, SubregionOrigin
<'tcx
>>>,
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.
201 // An example is a `A <= B` where neither `A` nor `B` are
202 // inference variables.
203 verifys
: RefCell
<Vec
<Verify
<'tcx
>>>,
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:
209 // foo.iter().filter(<'a> |x: &'a &'b T| ...)
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.
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
)>>,
224 lubs
: RefCell
<CombineMap
>,
225 glbs
: RefCell
<CombineMap
>,
226 skolemization_count
: Cell
<u32>,
227 bound_count
: Cell
<u32>,
229 // The undo log records actions that might later be undone.
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
238 undo_log
: RefCell
<Vec
<UndoLogEntry
>>,
239 unification_table
: RefCell
<UnificationTable
<ty
::RegionVid
>>,
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
>>>,
246 pub struct RegionSnapshot
{
248 region_snapshot
: unify
::Snapshot
<ty
::RegionVid
>,
249 skolemization_count
: u32,
252 impl<'a
, 'tcx
> RegionVarBindings
<'a
, 'tcx
> {
253 pub fn new(tcx
: &'a ty
::ctxt
<'tcx
>) -> RegionVarBindings
<'a
, '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()),
270 fn in_snapshot(&self) -> bool
{
271 !self.undo_log
.borrow().is_empty()
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
);
280 region_snapshot
: self.unification_table
.borrow_mut().snapshot(),
281 skolemization_count
: self.skolemization_count
.get(),
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
);
290 let mut undo_log
= self.undo_log
.borrow_mut();
291 if snapshot
.length
== 0 {
292 undo_log
.truncate(0);
294 (*undo_log
)[snapshot
.length
] = CommitedSnapshot
;
296 self.skolemization_count
.set(snapshot
.skolemization_count
);
297 self.unification_table
.borrow_mut().commit(snapshot
.region_snapshot
);
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() {
308 panic
!("Failure to observe stack discipline");
310 CommitedSnapshot
=> {}
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);
316 AddConstraint(ref constraint
) => {
317 self.constraints
.borrow_mut().remove(constraint
);
319 AddVerify(index
) => {
320 self.verifys
.borrow_mut().pop();
321 assert_eq
!(self.verifys
.borrow().len(), index
);
323 AddGiven(sub
, sup
) => {
324 self.givens
.borrow_mut().remove(&(sub
, sup
));
326 AddCombination(Glb
, ref regions
) => {
327 self.glbs
.borrow_mut().remove(regions
);
329 AddCombination(Lub
, ref regions
) => {
330 self.lubs
.borrow_mut().remove(regions
);
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
);
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
);
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());
352 let u_vid
= self.unification_table
.borrow_mut().new_key(
353 unify_key
::RegionVidKey { min_vid: vid }
355 assert_eq
!(vid
, u_vid
);
356 if self.in_snapshot() {
357 self.undo_log
.borrow_mut().push(AddVar(vid
));
359 debug
!("created new region variable {:?} with origin {:?}",
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.
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).
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
);
384 let sc
= self.skolemization_count
.get();
385 self.skolemization_count
.set(sc
+ 1);
386 ReSkolemized(ty
::SkolemizedRegionVid { index: sc }
, br
)
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.
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
408 let sc
= self.bound_count
.get();
409 self.bound_count
.set(sc
+ 1);
411 if sc
>= self.bound_count
.get() {
412 self.tcx
.sess
.bug("rollover in RegionInference new_bound()");
415 ReLateBound(debruijn
, BrFresh(sc
))
418 fn values_are_none(&self) -> bool
{
419 self.values
.borrow().is_none()
422 fn add_constraint(&self, constraint
: Constraint
, origin
: SubregionOrigin
<'tcx
>) {
423 // cannot add constraints once regions are resolved
424 assert
!(self.values_are_none());
426 debug
!("RegionVarBindings: add_constraint({:?})", constraint
);
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
));
435 fn add_verify(&self, verify
: Verify
<'tcx
>) {
436 // cannot add verifys once regions are resolved
437 assert
!(self.values_are_none());
439 debug
!("RegionVarBindings: add_verify({:?})", verify
);
441 // skip no-op cases known to be satisfied
443 VerifyGenericBound(_
, _
, _
, VerifyBound
::AllBounds(ref bs
)) if bs
.len() == 0 => {
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
));
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());
461 let mut givens
= self.givens
.borrow_mut();
462 if givens
.insert((sub
, sup
)) {
463 debug
!("add_given({:?} <= {:?})", sub
, sup
);
465 self.undo_log
.borrow_mut().push(AddGiven(sub
, sup
));
469 pub fn make_eqregion(&self, origin
: SubregionOrigin
<'tcx
>, sub
: Region
, sup
: Region
) {
471 // Eventually, it would be nice to add direct support for
473 self.make_subregion(origin
.clone(), sub
, sup
);
474 self.make_subregion(origin
, sup
, sub
);
476 if let (ty
::ReVar(sub
), ty
::ReVar(sup
)) = (sub
, sup
) {
477 self.unification_table
.borrow_mut().union(sub
, sup
);
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());
486 debug
!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}",
492 (ReEarlyBound(..), _
) |
493 (ReLateBound(..), _
) |
494 (_
, ReEarlyBound(..)) |
495 (_
, ReLateBound(..)) => {
496 self.tcx
.sess
.span_bug(origin
.span(),
497 &format
!("cannot relate bound region: {:?} <= {:?}",
502 // all regions are subregions of static, so we can ignore this
504 (ReVar(sub_id
), ReVar(sup_id
)) => {
505 self.add_constraint(ConstrainVarSubVar(sub_id
, sup_id
), origin
);
507 (r
, ReVar(sup_id
)) => {
508 self.add_constraint(ConstrainRegSubVar(r
, sup_id
), origin
);
510 (ReVar(sub_id
), r
) => {
511 self.add_constraint(ConstrainVarSubReg(sub_id
, r
), origin
);
514 self.add_verify(VerifyRegSubReg(origin
, sub
, sup
));
519 /// See `Verify::VerifyGenericBound`
520 pub fn verify_generic_bound(&self,
521 origin
: SubregionOrigin
<'tcx
>,
522 kind
: GenericKind
<'tcx
>,
524 bound
: VerifyBound
) {
525 self.add_verify(VerifyGenericBound(kind
, origin
, sub
, bound
));
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());
532 debug
!("RegionVarBindings: lub_regions({:?}, {:?})", a
, b
);
534 (ReStatic
, _
) | (_
, ReStatic
) => {
535 ReStatic
// nothing lives longer than static
539 self.combine_vars(Lub
, a
, b
, origin
.clone(), |this
, old_r
, new_r
| {
540 this
.make_subregion(origin
.clone(), old_r
, new_r
)
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());
550 debug
!("RegionVarBindings: glb_regions({:?}, {:?})", a
, b
);
552 (ReStatic
, r
) | (r
, ReStatic
) => {
553 // static lives longer than everything else
558 self.combine_vars(Glb
, a
, b
, origin
.clone(), |this
, old_r
, new_r
| {
559 this
.make_subregion(origin
.clone(), new_r
, old_r
)
565 pub fn resolve_var(&self, rid
: RegionVid
) -> ty
::Region
{
566 match *self.values
.borrow() {
568 self.tcx
.sess
.span_bug((*self.var_origins
.borrow())[rid
.index
as usize].span(),
569 "attempt to resolve region variable before values have \
572 Some(ref values
) => {
573 let r
= lookup(values
, rid
);
574 debug
!("resolve_var({:?}) = {:?}", rid
, r
);
580 pub fn opportunistic_resolve_var(&self, rid
: RegionVid
) -> ty
::Region
{
581 ty
::ReVar(self.unification_table
.borrow_mut().find_value(rid
).min_vid
)
584 fn combine_map(&self, t
: CombineMapType
) -> &RefCell
<CombineMap
> {
591 pub fn combine_vars
<F
>(&self,
595 origin
: SubregionOrigin
<'tcx
>,
598 where F
: FnMut(&RegionVarBindings
<'a
, 'tcx
>, Region
, Region
)
600 let vars
= TwoRegions { a: a, b: b }
;
601 match self.combine_map(t
).borrow().get(&vars
) {
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
));
612 relate(self, a
, ReVar(c
));
613 relate(self, b
, ReVar(c
));
614 debug
!("combine_vars() c={:?}", c
);
618 pub fn vars_created_since_snapshot(&self, mark
: &RegionSnapshot
) -> Vec
<RegionVid
> {
619 self.undo_log
.borrow()[mark
.length
..]
623 AddVar(vid
) => Some(vid
),
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();
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
);
647 for undo_entry
in self.undo_log
.borrow()[mark
.length
..].iter() {
649 &AddConstraint(ConstrainVarSubVar(a
, b
)) => {
650 consider_adding_bidirectional_edges(&mut result_set
, r
, ReVar(a
), ReVar(b
));
652 &AddConstraint(ConstrainRegSubVar(a
, b
)) => {
653 consider_adding_bidirectional_edges(&mut result_set
, r
, a
, ReVar(b
));
655 &AddConstraint(ConstrainVarSubReg(a
, b
)) => {
656 consider_adding_bidirectional_edges(&mut result_set
, r
, ReVar(a
), b
);
659 consider_adding_bidirectional_edges(&mut result_set
,
665 match (*self.verifys
.borrow())[i
] {
666 VerifyRegSubReg(_
, a
, b
) => {
667 consider_adding_bidirectional_edges(&mut result_set
, r
, a
, b
);
669 VerifyGenericBound(_
, _
, a
, ref bound
) => {
670 bound
.for_each_region(&mut |b
| {
671 consider_adding_bidirectional_edges(&mut result_set
, r
, a
, b
)
676 &AddCombination(..) |
679 &CommitedSnapshot
=> {}
688 fn consider_adding_bidirectional_edges(result_set
: &mut Vec
<Region
>,
692 consider_adding_directed_edge(result_set
, r
, r1
, r2
);
693 consider_adding_directed_edge(result_set
, r
, r2
, r1
);
696 fn consider_adding_directed_edge(result_set
: &mut Vec
<Region
>,
701 // Clearly, this is potentially inefficient.
702 if !result_set
.iter().any(|x
| *x
== r2
) {
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
);
725 fn lub_concrete_regions(&self, free_regions
: &FreeRegionMap
, a
: Region
, b
: Region
) -> Region
{
727 (ReLateBound(..), _
) |
728 (_
, ReLateBound(..)) |
729 (ReEarlyBound(..), _
) |
730 (_
, ReEarlyBound(..)) => {
731 self.tcx
.sess
.bug(&format
!("cannot relate bound region: LUB({:?}, {:?})", a
, b
));
734 (ReStatic
, _
) | (_
, ReStatic
) => {
735 ReStatic
// nothing lives longer than static
738 (ReEmpty
, r
) | (r
, ReEmpty
) => {
739 r
// everything lives longer than empty
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: {:?}, {:?}",
750 (ReFree(ref fr
), ReScope(s_id
)) |
751 (ReScope(s_id
), ReFree(ref 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
);
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
764 // otherwise, we don't know what the free region is,
765 // so we must conservatively say the LUB is static:
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
774 ReScope(self.tcx
.region_maps
.nearest_common_ancestor(a_id
, b_id
))
777 (ReFree(a_fr
), ReFree(b_fr
)) => {
778 free_regions
.lub_free_regions(a_fr
, b_fr
)
781 // For these types, we cannot define any additional
783 (ReSkolemized(..), _
) |
784 (_
, ReSkolemized(..)) => {
795 // ______________________________________________________________________
797 #[derive(Copy, Clone, Debug)]
807 struct RegionAndOrigin
<'tcx
> {
809 origin
: SubregionOrigin
<'tcx
>,
812 type RegionGraph
= graph
::Graph
<(), Constraint
>;
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
)
820 let mut var_data
= self.construct_var_data();
822 // Dorky hack to cause `dump_constraints` to only get called
823 // if debug mode is enabled:
824 debug
!("----() End constraint listing (subject={}) {:?}---",
826 self.dump_constraints(subject
));
827 graphviz
::maybe_print_constraints_for(self, subject
);
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
,
837 self.collect_concrete_region_errors(free_regions
, &values
, errors
);
841 fn construct_var_data(&self) -> Vec
<VarData
> {
842 (0..self.num_vars() as usize)
843 .map(|_
| VarData { value: Value(ty::ReEmpty) }
)
847 fn dump_constraints(&self, subject
: ast
::NodeId
) {
848 debug
!("----() Start constraint listing (subject={}) ()----",
850 for (idx
, (constraint
, _
)) in self.constraints
.borrow().iter().enumerate() {
851 debug
!("Constraint {} => {:?}", idx
, constraint
);
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:
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
));
880 fn expansion(&self, free_regions
: &FreeRegionMap
, var_data
: &mut [VarData
]) {
881 self.iterate_until_fixed_point("Expansion", |constraint
| {
882 debug
!("expansion: constraint={:?} origin={:?}",
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
)
893 ConstrainVarSubVar(a_vid
, b_vid
) => {
894 match var_data
[a_vid
.index
as usize].value
{
897 let b_node
= &mut var_data
[b_vid
.index
as usize];
898 self.expand_node(free_regions
, a_region
, b_vid
, b_node
)
902 ConstrainVarSubReg(..) => {
903 // This is a contraction constraint. Ignore it.
910 fn expand_node(&self,
911 free_regions
: &FreeRegionMap
,
914 b_data
: &mut VarData
)
916 debug
!("expand_node({:?}, {:?} == {:?})",
921 // Check if this relationship is implied by a given.
924 if self.givens
.borrow().contains(&(fr
, b_vid
)) {
933 Value(cur_region
) => {
934 let lub
= self.lub_concrete_regions(free_regions
, a_region
, cur_region
);
935 if lub
== cur_region
{
939 debug
!("Expanding value of {:?} from {:?} to {:?}",
944 b_data
.value
= Value(lub
);
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={:?}",
964 ConstrainRegSubVar(..) |
965 ConstrainVarSubVar(..) => {
966 // Expansion will ensure that these constraints hold. Ignore.
968 ConstrainVarSubReg(a_vid
, b_region
) => {
969 let a_data
= &mut var_data
[a_vid
.index
as usize];
970 debug
!("contraction: {:?} == {:?}, {:?}",
975 let a_region
= match a_data
.value
{
976 ErrorValue
=> return false,
977 Value(a_region
) => a_region
,
980 if !free_regions
.is_subregion_of(self.tcx
, a_region
, b_region
) {
981 debug
!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
985 a_data
.value
= ErrorValue
;
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() {
1001 VerifyRegSubReg(ref origin
, sub
, sup
) => {
1002 if free_regions
.is_subregion_of(self.tcx
, sub
, sup
) {
1006 if !reg_reg_dups
.insert((sub
, sup
)) {
1010 debug
!("region inference error at {:?}: {:?} <= {:?} is not true",
1015 errors
.push(ConcreteFailure((*origin
).clone(), sub
, sup
));
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
) {
1024 debug
!("region inference error at {:?}: verifying {:?} <= {:?}",
1029 errors
.push(GenericBoundFailure((*origin
).clone(), kind
.clone(), sub
));
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
>>)
1041 debug
!("extract_values_and_collect_conflicts()");
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];
1056 for idx
in 0..self.num_vars() as usize {
1057 match var_data
[idx
].value
{
1059 /* Inference successful */
1062 /* Inference impossible, this value contains
1063 inconsistent constraints.
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
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.
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. =) */
1085 let node_vid
= RegionVid { index: idx as u32 }
;
1086 self.collect_error_for_expanding_node(free_regions
,
1095 (0..self.num_vars() as usize).map(|idx
| var_data
[idx
].value
).collect()
1098 fn construct_graph(&self) -> RegionGraph
{
1099 let num_vars
= self.num_vars();
1101 let constraints
= self.constraints
.borrow();
1103 let mut graph
= graph
::Graph
::new();
1105 for _
in 0..num_vars
{
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(());
1117 for (constraint
, _
) in constraints
.iter() {
1119 ConstrainVarSubVar(a_id
, b_id
) => {
1120 graph
.add_edge(NodeIndex(a_id
.index
as usize),
1121 NodeIndex(b_id
.index
as usize),
1124 ConstrainRegSubVar(_
, b_id
) => {
1125 graph
.add_edge(dummy_source
, NodeIndex(b_id
.index
as usize), *constraint
);
1127 ConstrainVarSubReg(a_id
, _
) => {
1128 graph
.add_edge(NodeIndex(a_id
.index
as usize), dummy_sink
, *constraint
);
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
,
1148 let (mut upper_bounds
, upper_dup
) = self.collect_concrete_regions(graph
,
1153 if lower_dup
|| upper_dup
{
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
,
1168 lower_bounds
.sort_by(|a
, b
| free_regions_first(a
, b
));
1169 upper_bounds
.sort_by(|a
, b
| free_regions_first(a
, b
));
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: {:?} \
1180 upper_bound
.region
);
1181 errors
.push(SubSupConflict(origin
,
1182 lower_bound
.origin
.clone(),
1184 upper_bound
.origin
.clone(),
1185 upper_bound
.region
));
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={:?}, \
1200 fn collect_concrete_regions(&self,
1201 graph
: &RegionGraph
,
1202 orig_node_idx
: RegionVid
,
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
>>,
1212 let mut state
= WalkState
{
1214 stack
: vec
![orig_node_idx
],
1218 state
.set
.insert(orig_node_idx
);
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
);
1224 while !state
.stack
.is_empty() {
1225 let node_idx
= state
.stack
.pop().unwrap();
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;
1234 debug
!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
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
);
1244 let WalkState {result, dup_found, ..}
= state
;
1245 return (result
, dup_found
);
1247 fn process_edges
<'a
, 'tcx
>(this
: &RegionVarBindings
<'a
, 'tcx
>,
1248 state
: &mut WalkState
<'tcx
>,
1249 graph
: &RegionGraph
,
1250 source_vid
: RegionVid
,
1252 debug
!("process_edges(source_vid={:?}, dir={:?})", source_vid
, dir
);
1254 let source_node_index
= NodeIndex(source_vid
.index
as usize);
1255 for (_
, edge
) in graph
.adjacent_edges(source_node_index
, dir
) {
1257 ConstrainVarSubVar(from_vid
, to_vid
) => {
1258 let opp_vid
= if from_vid
== source_vid
{
1263 if state
.set
.insert(opp_vid
) {
1264 state
.stack
.push(opp_vid
);
1268 ConstrainRegSubVar(region
, _
) |
1269 ConstrainVarSubReg(_
, region
) => {
1270 state
.result
.push(RegionAndOrigin
{
1272 origin
: this
.constraints
.borrow().get(&edge
.data
).unwrap().clone(),
1280 fn iterate_until_fixed_point
<F
>(&self, tag
: &str, mut body
: F
)
1281 where F
: FnMut(&Constraint
) -> bool
1283 let mut iteration
= 0;
1284 let mut changed
= true;
1288 debug
!("---- {} Iteration {}{}", "#", tag
, iteration
);
1289 for (constraint
, _
) in self.constraints
.borrow().iter() {
1290 let edge_changed
= body(constraint
);
1292 debug
!("Updated due to constraint {:?}", constraint
);
1297 debug
!("---- {} Complete after {} iteration(s)", tag
, iteration
);
1302 impl<'tcx
> fmt
::Debug
for Verify
<'tcx
> {
1303 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1305 VerifyRegSubReg(_
, ref a
, ref b
) => {
1306 write
!(f
, "VerifyRegSubReg({:?}, {:?})", a
, b
)
1308 VerifyGenericBound(_
, ref p
, ref a
, ref bs
) => {
1309 write
!(f
, "VerifyGenericBound({:?}, {:?}, {:?})", p
, a
, bs
)
1315 fn normalize(values
: &Vec
<VarValue
>, r
: ty
::Region
) -> ty
::Region
{
1317 ty
::ReVar(rid
) => lookup(values
, rid
),
1322 fn lookup(values
: &Vec
<VarValue
>, rid
: ty
::RegionVid
) -> ty
::Region
{
1323 match values
[rid
.index
as usize] {
1325 ErrorValue
=> ReStatic
, // Previously reported error.
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
)
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
)
1342 impl<'tcx
> fmt
::Debug
for GenericKind
<'tcx
> {
1343 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1345 GenericKind
::Param(ref p
) => write
!(f
, "{:?}", p
),
1346 GenericKind
::Projection(ref p
) => write
!(f
, "{:?}", p
),
1351 impl<'tcx
> fmt
::Display
for GenericKind
<'tcx
> {
1352 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1354 GenericKind
::Param(ref p
) => write
!(f
, "{}", p
),
1355 GenericKind
::Projection(ref p
) => write
!(f
, "{}", p
),
1360 impl<'tcx
> GenericKind
<'tcx
> {
1361 pub fn to_ty(&self, tcx
: &ty
::ctxt
<'tcx
>) -> Ty
<'tcx
> {
1363 GenericKind
::Param(ref p
) => p
.to_ty(tcx
),
1364 GenericKind
::Projection(ref p
) => tcx
.mk_projection(p
.trait_ref
.clone(), p
.item_name
),
1370 fn for_each_region(&self, f
: &mut FnMut(ty
::Region
)) {
1372 &VerifyBound
::AnyRegion(ref rs
) |
1373 &VerifyBound
::AllRegions(ref rs
) => for &r
in rs
{
1377 &VerifyBound
::AnyBound(ref bs
) |
1378 &VerifyBound
::AllBounds(ref bs
) => for b
in bs
{
1379 b
.for_each_region(f
);
1384 pub fn must_hold(&self) -> bool
{
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()),
1393 pub fn cannot_hold(&self) -> bool
{
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()),
1402 pub fn or(self, vb
: VerifyBound
) -> VerifyBound
{
1403 if self.must_hold() || vb
.cannot_hold() {
1405 } else if self.cannot_hold() || vb
.must_hold() {
1408 VerifyBound
::AnyBound(vec
![self, vb
])
1412 pub fn and(self, vb
: VerifyBound
) -> VerifyBound
{
1413 if self.must_hold() && vb
.must_hold() {
1415 } else if self.cannot_hold() && vb
.cannot_hold() {
1418 VerifyBound
::AllBounds(vec
![self, vb
])
1422 fn is_met
<'tcx
>(&self,
1423 tcx
: &ty
::ctxt
<'tcx
>,
1424 free_regions
: &FreeRegionMap
,
1425 var_values
: &Vec
<VarValue
>,
1429 &VerifyBound
::AnyRegion(ref rs
) =>
1431 .map(|&r
| normalize(var_values
, r
))
1432 .any(|r
| free_regions
.is_subregion_of(tcx
, min
, r
)),
1434 &VerifyBound
::AllRegions(ref rs
) =>
1436 .map(|&r
| normalize(var_values
, r
))
1437 .all(|r
| free_regions
.is_subregion_of(tcx
, min
, r
)),
1439 &VerifyBound
::AnyBound(ref bs
) =>
1441 .any(|b
| b
.is_met(tcx
, free_regions
, var_values
, min
)),
1443 &VerifyBound
::AllBounds(ref bs
) =>
1445 .all(|b
| b
.is_met(tcx
, free_regions
, var_values
, min
)),