Skip to content

Commit 22cd041

Browse files
committed
move the region_obligations processing code into InferCtxt
1 parent d73be85 commit 22cd041

File tree

5 files changed

+236
-90
lines changed

5 files changed

+236
-90
lines changed

src/librustc/infer/mod.rs

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mod higher_ranked;
5555
pub mod lattice;
5656
mod lub;
5757
pub mod region_inference;
58+
mod region_obligations;
5859
pub mod resolve;
5960
mod freshen;
6061
mod sub;
@@ -160,6 +161,13 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
160161
// regionck to be sure that it has found *all* the region
161162
// obligations (otherwise, it's easy to fail to walk to a
162163
// particular node-id).
164+
//
165+
// Before running `resolve_regions_and_report_errors`, the creator
166+
// of the inference context is expected to invoke
167+
// `process_region_obligations` (defined in `self::region_obligations`)
168+
// for each body-id in this map, which will process the
169+
// obligations within. This is expected to be done 'late enough'
170+
// that all type inference variables have been bound and so forth.
163171
region_obligations: RefCell<NodeMap<Vec<RegionObligation<'tcx>>>>,
164172
}
165173

@@ -984,33 +992,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
984992
})
985993
}
986994

987-
/// Registers that the given region obligation must be resolved
988-
/// from within the scope of `body_id`. These regions are enqueued
989-
/// and later processed by regionck, when full type information is
990-
/// available (see `region_obligations` field for more
991-
/// information).
992-
pub fn register_region_obligation(&self,
993-
body_id: ast::NodeId,
994-
obligation: RegionObligation<'tcx>)
995-
{
996-
self.region_obligations.borrow_mut().entry(body_id)
997-
.or_insert(vec![])
998-
.push(obligation);
999-
}
1000-
1001-
/// Get the region obligations that must be proven (during
1002-
/// `regionck`) for the given `body_id` (removing them from the
1003-
/// map as a side-effect).
1004-
pub fn take_region_obligations(&self,
1005-
body_id: ast::NodeId)
1006-
-> Vec<RegionObligation<'tcx>>
1007-
{
1008-
match self.region_obligations.borrow_mut().remove(&body_id) {
1009-
None => vec![],
1010-
Some(vec) => vec,
1011-
}
1012-
}
1013-
1014995
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
1015996
self.type_variables
1016997
.borrow_mut()

src/librustc_typeck/check/regionck_outlives.rs renamed to src/librustc/infer/region_obligations.rs

Lines changed: 203 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,210 @@
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;
863
use syntax::ast;
964
use syntax_pos::Span;
1065

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.
13195
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
14196
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
15197
implicit_region_bound: Option<ty::Region<'tcx>>,
16198
param_env: ty::ParamEnv<'tcx>,
17199
body_id: ast::NodeId,
18200

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.
20203
obligations: PredicateObligations<'tcx>,
21204
}
22205

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(
25208
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
26209
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
27210
implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -38,6 +221,12 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
38221
}
39222
}
40223

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+
41230
/// Adds constraints to inference such that `T: 'a` holds (or
42231
/// reports an error if it cannot).
43232
///
@@ -46,22 +235,7 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
46235
/// - `origin`, the reason we need this constraint
47236
/// - `ty`, the type `T`
48237
/// - `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(
65239
&mut self,
66240
origin: infer::SubregionOrigin<'tcx>,
67241
ty: Ty<'tcx>,
@@ -199,7 +373,7 @@ impl<'cx, 'gcx, 'tcx> RegionckOutlives<'cx, 'gcx, 'tcx> {
199373
debug!("projection_must_outlive: no declared bounds");
200374

201375
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);
203377
}
204378

205379
for r in projection_ty.substs.regions() {

src/librustc/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
543543
// it, and it would take some refactoring to stop doing so.
544544
// (In particular, the needed methods currently live in
545545
// regionck.) -nmatsakis
546-
let _ = infcx.take_region_obligations(body_id);
546+
let _ = infcx.ignore_region_obligations(body_id);
547547

548548
infcx.resolve_regions_and_report_errors(region_context, &region_scope_tree, &free_regions);
549549
let predicates = match infcx.fully_resolve(&predicates) {

src/librustc_typeck/check/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ pub mod dropck;
137137
pub mod _match;
138138
pub mod writeback;
139139
mod regionck;
140-
mod regionck_outlives;
141140
pub mod coercion;
142141
pub mod demand;
143142
pub mod method;

0 commit comments

Comments
 (0)