1
- //! Temporary holding spot for some code I want to factor out.
2
-
3
- use rustc:: traits:: { self , ObligationCause , ObligationCauseCode , PredicateObligations } ;
4
- use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
5
- use rustc:: infer:: { self , GenericKind , InferCtxt , InferOk , VerifyBound } ;
6
- use rustc:: ty:: subst:: Subst ;
7
- use rustc:: ty:: outlives:: Component ;
1
+ //! Code that handles "type-outlives" constraints like `T: 'a`. This
2
+ //! is based on the `outlives_components` function defined on the tcx,
3
+ //! but it adds a bit of heuristics on top, in particular to deal with
4
+ //! associated types and projections.
5
+ //!
6
+ //! When we process a given `T: 'a` obligation, we may produce two
7
+ //! kinds of constraints for the region inferencer:
8
+ //!
9
+ //! - Relationships between inference variables and other regions.
10
+ //! For example, if we have `&'?0 u32: 'a`, then we would produce
11
+ //! a constraint that `'a <= '?0`.
12
+ //! - "Verifys" that must be checked after inferencing is done.
13
+ //! For example, if we know that, for some type parameter `T`,
14
+ //! `T: 'a + 'b`, and we have a requirement that `T: '?1`,
15
+ //! then we add a "verify" that checks that `'?1 <= 'a || '?1 <= 'b`.
16
+ //! - Note the difference with the previous case: here, the region
17
+ //! variable must be less than something else, so this doesn't
18
+ //! affect how inference works (it finds the smallest region that
19
+ //! will do); it's just a post-condition that we have to check.
20
+ //!
21
+ //! **The key point is that once this function is done, we have
22
+ //! reduced all of our "type-region outlives" obligations into relationships
23
+ //! between individual regions.**
24
+ //!
25
+ //! One key input to this function is the set of "region-bound pairs".
26
+ //! These are basically the relationships between type parameters and
27
+ //! regions that are in scope at the point where the outlives
28
+ //! obligation was incurred. **When type-checking a function,
29
+ //! particularly in the face of closures, this is not known until
30
+ //! regionck runs!** This is because some of those bounds come
31
+ //! from things we have yet to infer.
32
+ //!
33
+ //! Consider:
34
+ //!
35
+ //! ```
36
+ //! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T));
37
+ //! fn foo<T>(x: T) {
38
+ //! bar(x, |y| { ... })
39
+ //! // ^ closure arg
40
+ //! }
41
+ //! ```
42
+ //!
43
+ //! Here, the type of `y` may involve inference variables and the
44
+ //! like, and it may also contain implied bounds that are needed to
45
+ //! type-check the closure body (e.g., here it informs us that `T`
46
+ //! outlives the late-bound region `'a`).
47
+ //!
48
+ //! > That said, in writing this, I have come to wonder: this
49
+ //! inference dependency, I think, is only interesting for
50
+ //! late-bound regions in the closure -- if the region appears free
51
+ //! in the closure signature, then the relationship must be known to
52
+ //! the caller (here, `foo`), and hence could be verified earlier
53
+ //! up. Moreover, we infer late-bound regions quite early on right
54
+ //! now, i.e., only when the expected signature is known. So we
55
+ //! *may* be able to sidestep this. Regardless, once the NLL
56
+ //! transition is complete, this concern will be gone. -nmatsakis
57
+
58
+ use infer:: { self , GenericKind , InferCtxt , InferOk , RegionObligation , SubregionOrigin , VerifyBound } ;
59
+ use traits:: { self , ObligationCause , ObligationCauseCode , PredicateObligations } ;
60
+ use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
61
+ use ty:: subst:: Subst ;
62
+ use ty:: outlives:: Component ;
8
63
use syntax:: ast;
9
64
use syntax_pos:: Span ;
10
65
11
- pub struct RegionckOutlives < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
12
- // Context provided by the caller:
66
+ impl < ' cx , ' gcx , ' tcx > InferCtxt < ' cx , ' gcx , ' tcx > {
67
+ /// Registers that the given region obligation must be resolved
68
+ /// from within the scope of `body_id`. These regions are enqueued
69
+ /// and later processed by regionck, when full type information is
70
+ /// available (see `region_obligations` field for more
71
+ /// information).
72
+ pub fn register_region_obligation (
73
+ & self ,
74
+ body_id : ast:: NodeId ,
75
+ obligation : RegionObligation < ' tcx > ,
76
+ ) {
77
+ self . region_obligations
78
+ . borrow_mut ( )
79
+ . entry ( body_id)
80
+ . or_insert ( vec ! [ ] )
81
+ . push ( obligation) ;
82
+ }
83
+
84
+ /// Process the region obligations that must be proven (during
85
+ /// `regionck`) for the given `body_id`, given information about
86
+ /// the region bounds in scope and so forth. This function must be
87
+ /// invoked for all relevant body-ids before region inference is
88
+ /// done (or else an assert will fire).
89
+ ///
90
+ /// See the `region_obligations` field of `InferCtxt` for some
91
+ /// comments about how this funtion fits into the overall expected
92
+ /// flow of the the inferencer. The key point is that it is
93
+ /// invoked after all type-inference variables have been bound --
94
+ /// towards the end of regionck. This also ensures that the
95
+ /// region-bound-pairs are available (see comments above regarding
96
+ /// closures).
97
+ ///
98
+ /// # Parameters
99
+ ///
100
+ /// - `region_bound_pairs`: the set of region bounds implied by
101
+ /// the parameters and where-clauses. In particular, each pair
102
+ /// `('a, K)` in this list tells us that the bounds in scope
103
+ /// indicate that `K: 'a`, where `K` is either a generic
104
+ /// parameter like `T` or a projection like `T::Item`.
105
+ /// - `implicit_region_bound`: if some, this is a region bound
106
+ /// that is considered to hold for all type parameters (the
107
+ /// function body).
108
+ /// - `param_env` is the parameter environment for the enclosing function.
109
+ /// - `body_id` is the body-id whose region obligations are being
110
+ /// processed.
111
+ ///
112
+ /// # Returns
113
+ ///
114
+ /// This function may have to perform normalizations, and hence it
115
+ /// returns an `InferOk` with subobligations that must be
116
+ /// processed.
117
+ pub fn process_registered_region_obligations (
118
+ & self ,
119
+ region_bound_pairs : & [ ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) ] ,
120
+ implicit_region_bound : Option < ty:: Region < ' tcx > > ,
121
+ param_env : ty:: ParamEnv < ' tcx > ,
122
+ body_id : ast:: NodeId ,
123
+ ) -> InferOk < ' tcx , ( ) > {
124
+ let region_obligations = match self . region_obligations . borrow_mut ( ) . remove ( & body_id) {
125
+ None => vec ! [ ] ,
126
+ Some ( vec) => vec,
127
+ } ;
128
+
129
+ let mut outlives = TypeOutlives :: new (
130
+ self ,
131
+ region_bound_pairs,
132
+ implicit_region_bound,
133
+ param_env,
134
+ body_id,
135
+ ) ;
136
+
137
+ for RegionObligation {
138
+ sup_type,
139
+ sub_region,
140
+ cause,
141
+ } in region_obligations
142
+ {
143
+ let origin = SubregionOrigin :: from_obligation_cause (
144
+ & cause,
145
+ || infer:: RelateParamBound ( cause. span , sup_type) ,
146
+ ) ;
147
+
148
+ outlives. type_must_outlive ( origin, sup_type, sub_region) ;
149
+ }
150
+
151
+ InferOk {
152
+ value : ( ) ,
153
+ obligations : outlives. into_accrued_obligations ( ) ,
154
+ }
155
+ }
156
+
157
+ /// Processes a single ad-hoc region obligation that was not
158
+ /// registered in advance.
159
+ pub fn type_must_outlive (
160
+ & self ,
161
+ region_bound_pairs : & [ ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) ] ,
162
+ implicit_region_bound : Option < ty:: Region < ' tcx > > ,
163
+ param_env : ty:: ParamEnv < ' tcx > ,
164
+ body_id : ast:: NodeId ,
165
+ origin : infer:: SubregionOrigin < ' tcx > ,
166
+ ty : Ty < ' tcx > ,
167
+ region : ty:: Region < ' tcx > ,
168
+ ) -> InferOk < ' tcx , ( ) > {
169
+ let mut outlives = TypeOutlives :: new (
170
+ self ,
171
+ region_bound_pairs,
172
+ implicit_region_bound,
173
+ param_env,
174
+ body_id,
175
+ ) ;
176
+ outlives. type_must_outlive ( origin, ty, region) ;
177
+ InferOk {
178
+ value : ( ) ,
179
+ obligations : outlives. into_accrued_obligations ( ) ,
180
+ }
181
+ }
182
+
183
+ /// Ignore the region obligations for a given `body_id`, not bothering to
184
+ /// prove them. This function should not really exist; it is used to accommodate some older
185
+ /// code for the time being.
186
+ pub fn ignore_region_obligations ( & self , body_id : ast:: NodeId ) {
187
+ self . region_obligations . borrow_mut ( ) . remove ( & body_id) ;
188
+ }
189
+ }
190
+
191
+ #[ must_use] // you ought to invoke `into_accrued_obligations` when you are done =)
192
+ struct TypeOutlives < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
193
+ // See the comments on `process_registered_region_obligations` for the meaning
194
+ // of these fields.
13
195
infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
14
196
region_bound_pairs : & ' cx [ ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) ] ,
15
197
implicit_region_bound : Option < ty:: Region < ' tcx > > ,
16
198
param_env : ty:: ParamEnv < ' tcx > ,
17
199
body_id : ast:: NodeId ,
18
200
19
- // Obligations that we accrue as we go:
201
+ /// These are sub-obligations that we accrue as we go; they result
202
+ /// from any normalizations we had to do.
20
203
obligations : PredicateObligations < ' tcx > ,
21
204
}
22
205
23
- impl < ' cx , ' gcx , ' tcx > RegionckOutlives < ' cx , ' gcx , ' tcx > {
24
- pub fn new (
206
+ impl < ' cx , ' gcx , ' tcx > TypeOutlives < ' cx , ' gcx , ' tcx > {
207
+ fn new (
25
208
infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
26
209
region_bound_pairs : & ' cx [ ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) ] ,
27
210
implicit_region_bound : Option < ty:: Region < ' tcx > > ,
@@ -38,6 +221,12 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
38
221
}
39
222
}
40
223
224
+ /// Returns the obligations that accrued as a result of the
225
+ /// `type_must_outlive` calls.
226
+ fn into_accrued_obligations ( self ) -> PredicateObligations < ' tcx > {
227
+ self . obligations
228
+ }
229
+
41
230
/// Adds constraints to inference such that `T: 'a` holds (or
42
231
/// reports an error if it cannot).
43
232
///
@@ -46,22 +235,7 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
46
235
/// - `origin`, the reason we need this constraint
47
236
/// - `ty`, the type `T`
48
237
/// - `region`, the region `'a`
49
- pub fn type_must_outlive (
50
- mut self ,
51
- origin : infer:: SubregionOrigin < ' tcx > ,
52
- ty : Ty < ' tcx > ,
53
- region : ty:: Region < ' tcx > ,
54
- ) -> InferOk < ' tcx , ( ) > {
55
- self . type_must_outlive_pushing_obligations ( origin, ty, region) ;
56
- InferOk {
57
- value : ( ) ,
58
- obligations : self . obligations ,
59
- }
60
- }
61
-
62
- /// Internal helper: ensure that `ty_must_outlive` and push obligations onto
63
- /// our internal vector.
64
- fn type_must_outlive_pushing_obligations (
238
+ fn type_must_outlive (
65
239
& mut self ,
66
240
origin : infer:: SubregionOrigin < ' tcx > ,
67
241
ty : Ty < ' tcx > ,
@@ -199,7 +373,7 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
199
373
debug ! ( "projection_must_outlive: no declared bounds" ) ;
200
374
201
375
for component_ty in projection_ty. substs . types ( ) {
202
- self . type_must_outlive_pushing_obligations ( origin. clone ( ) , component_ty, region) ;
376
+ self . type_must_outlive ( origin. clone ( ) , component_ty, region) ;
203
377
}
204
378
205
379
for r in projection_ty. substs . regions ( ) {
0 commit comments