Module rustc_trait_selection::infer::outlives::obligations
source · [−]Expand description
Code that handles “type-outlives” constraints like T: 'a
. This
is based on the push_outlives_components
function defined in rustc_infer,
but it adds a bit of heuristics on top, in particular to deal with
associated types and projections.
When we process a given T: 'a
obligation, we may produce two
kinds of constraints for the region inferencer:
- Relationships between inference variables and other regions.
For example, if we have
&'?0 u32: 'a
, then we would produce a constraint that'a <= '?0
. - “Verifys” that must be checked after inferencing is done.
For example, if we know that, for some type parameter
T
,T: 'a + 'b
, and we have a requirement thatT: '?1
, then we add a “verify” that checks that'?1 <= 'a || '?1 <= 'b
.- Note the difference with the previous case: here, the region variable must be less than something else, so this doesn’t affect how inference works (it finds the smallest region that will do); it’s just a post-condition that we have to check.
The key point is that once this function is done, we have reduced all of our “type-region outlives” obligations into relationships between individual regions.
One key input to this function is the set of “region-bound pairs”. These are basically the relationships between type parameters and regions that are in scope at the point where the outlives obligation was incurred. When type-checking a function, particularly in the face of closures, this is not known until regionck runs! This is because some of those bounds come from things we have yet to infer.
Consider:
fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)) {}
fn foo<T>(x: T) {
bar(x, |y| { /* ... */})
// ^ closure arg
}
Here, the type of y
may involve inference variables and the
like, and it may also contain implied bounds that are needed to
type-check the closure body (e.g., here it informs us that T
outlives the late-bound region 'a
).
Note that by delaying the gathering of implied bounds until all
inference information is known, we may find relationships between
bound regions and other regions in the environment. For example,
when we first check a closure like the one expected as argument
to foo
:
fn foo<U, F: for<'a> FnMut(&'a U)>(_f: F) {}
the type of the closure’s first argument would be &'a ?U
. We
might later infer ?U
to something like &'b u32
, which would
imply that 'b: 'a
.
Structs
TypeOutlives
struct has the job of “lowering” a T: 'a
obligation into a series of 'a: 'b
constraints and “verify“s, as
described on the module comment. The final constraints are emitted
via a “delegate” of type D
– this is usually the infcx
, which
accrues them into the region_obligations
code, but for NLL we
use something else.