pub struct RegionInferenceContext<'tcx> {Show 17 fields
pub var_infos: VarInfos,
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
constraints: Frozen<OutlivesConstraintSet<'tcx>>,
constraint_graph: Frozen<ConstraintGraph<Normal>>,
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
rev_scc_graph: Option<Rc<ReverseSccGraph>>,
member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
member_constraints_applied: Vec<AppliedMemberConstraint>,
closure_bounds_mapping: FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
universe_causes: FxHashMap<UniverseIndex, UniverseInfo<'tcx>>,
scc_universes: IndexVec<ConstraintSccIndex, UniverseIndex>,
scc_representatives: IndexVec<ConstraintSccIndex, RegionVid>,
scc_values: RegionValues<ConstraintSccIndex>,
type_tests: Vec<TypeTest<'tcx>>,
universal_regions: Rc<UniversalRegions<'tcx>>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
}
Fields
var_infos: VarInfos
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>
Contains the definition for every region variable. Region
variables are identified by their index (RegionVid
). The
definition contains information about where the region came
from as well as its final inferred value.
liveness_constraints: LivenessValues<RegionVid>
The liveness constraints added to each region. For most
regions, these start out empty and steadily grow, though for
each universally quantified region R they start out containing
the entire CFG and end(R)
.
constraints: Frozen<OutlivesConstraintSet<'tcx>>
The outlives constraints computed by the type-check.
constraint_graph: Frozen<ConstraintGraph<Normal>>
The constraint-set, but in graph form, making it easy to traverse
the constraints adjacent to a particular region. Used to construct
the SCC (see constraint_sccs
) and for error reporting.
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>
The SCC computed from constraints
and the constraint
graph. We have an edge from SCC A to SCC B if A: B
. Used to
compute the values of each region.
rev_scc_graph: Option<Rc<ReverseSccGraph>>
Reverse of the SCC constraint graph – i.e., an edge A -> B
exists if
B: A
. This is used to compute the universal regions that are required
to outlive a given SCC. Computed lazily.
member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>
The “R0 member of [R1..Rn]” constraints, indexed by SCC.
member_constraints_applied: Vec<AppliedMemberConstraint>
Records the member constraints that we applied to each scc.
This is useful for error reporting. Once constraint
propagation is done, this vector is sorted according to
member_region_scc
.
closure_bounds_mapping: FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>
Map closure bounds to a Span
that should be used for error reporting.
universe_causes: FxHashMap<UniverseIndex, UniverseInfo<'tcx>>
Map universe indexes to information on why we created it.
scc_universes: IndexVec<ConstraintSccIndex, UniverseIndex>
Contains the minimum universe of any variable within the same SCC. We will ensure that no SCC contains values that are not visible from this index.
scc_representatives: IndexVec<ConstraintSccIndex, RegionVid>
Contains a “representative” from each SCC. This will be the minimal RegionVid belonging to that universe. It is used as a kind of hacky way to manage checking outlives relationships, since we can ‘canonicalize’ each region to the representative of its SCC and be sure that – if they have the same repr – they must be equal (though not having the same repr does not mean they are unequal).
scc_values: RegionValues<ConstraintSccIndex>
The final inferred values of the region variables; we compute one value per SCC. To get the value for any given region, you first find which scc it is a part of.
type_tests: Vec<TypeTest<'tcx>>
Type constraints that we check after solving.
universal_regions: Rc<UniversalRegions<'tcx>>
Information about the universally quantified regions in scope on this function.
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>
Information about how the universally quantified regions in scope on this function relate to one another.
Implementations
sourceimpl<'tcx> RegionInferenceContext<'tcx>
impl<'tcx> RegionInferenceContext<'tcx>
pub(crate) fn get_var_name_and_span_for_region(
&self,
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local_names: &IndexVec<Local, Option<Symbol>>,
upvars: &[Upvar<'tcx>],
fr: RegionVid
) -> Option<(Option<Symbol>, Span)>
sourcepub(crate) fn get_upvar_index_for_region(
&self,
tcx: TyCtxt<'tcx>,
fr: RegionVid
) -> Option<usize>
pub(crate) fn get_upvar_index_for_region(
&self,
tcx: TyCtxt<'tcx>,
fr: RegionVid
) -> Option<usize>
Search the upvars (if any) to find one that references fr. Return its index.
sourcepub(crate) fn get_upvar_name_and_span_for_region(
&self,
tcx: TyCtxt<'tcx>,
upvars: &[Upvar<'tcx>],
upvar_index: usize
) -> (Symbol, Span)
pub(crate) fn get_upvar_name_and_span_for_region(
&self,
tcx: TyCtxt<'tcx>,
upvars: &[Upvar<'tcx>],
upvar_index: usize
) -> (Symbol, Span)
Given the index of an upvar, finds its name and the span from where it was declared.
sourcepub(crate) fn get_argument_index_for_region(
&self,
tcx: TyCtxt<'tcx>,
fr: RegionVid
) -> Option<usize>
pub(crate) fn get_argument_index_for_region(
&self,
tcx: TyCtxt<'tcx>,
fr: RegionVid
) -> Option<usize>
Search the argument types for one that references fr (which should be a free region). Returns Some(_) with the index of the input if one is found.
N.B., in the case of a closure, the index is indexing into the signature as seen by the user - in particular, index 0 is not the implicit self parameter.
sourceimpl<'tcx> RegionInferenceContext<'tcx>
impl<'tcx> RegionInferenceContext<'tcx>
sourcepub(crate) fn dump_mir(
&self,
tcx: TyCtxt<'tcx>,
out: &mut dyn Write
) -> Result<()>
pub(crate) fn dump_mir(
&self,
tcx: TyCtxt<'tcx>,
out: &mut dyn Write
) -> Result<()>
Write out our state into the .mir
files.
sourcefn for_each_constraint(
&self,
tcx: TyCtxt<'tcx>,
with_msg: &mut dyn FnMut(&str) -> Result<()>
) -> Result<()>
fn for_each_constraint(
&self,
tcx: TyCtxt<'tcx>,
with_msg: &mut dyn FnMut(&str) -> Result<()>
) -> Result<()>
Debugging aid: Invokes the with_msg
callback repeatedly with
our internal region constraints. These are dumped into the
-Zdump-mir file so that we can figure out why the region
inference resulted in the values that it did when debugging.
sourceimpl<'tcx> RegionInferenceContext<'tcx>
impl<'tcx> RegionInferenceContext<'tcx>
sourcepub(crate) fn dump_graphviz_raw_constraints(
&self,
w: &mut dyn Write
) -> Result<()>
pub(crate) fn dump_graphviz_raw_constraints(
&self,
w: &mut dyn Write
) -> Result<()>
Write out the region constraint graph.
sourcepub(crate) fn dump_graphviz_scc_constraints(
&self,
w: &mut dyn Write
) -> Result<()>
pub(crate) fn dump_graphviz_scc_constraints(
&self,
w: &mut dyn Write
) -> Result<()>
Write out the region constraint graph.
sourceimpl<'tcx> RegionInferenceContext<'tcx>
impl<'tcx> RegionInferenceContext<'tcx>
sourcepub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>>
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>>
Resolve any opaque types that were encountered while borrow checking
this item. This is then used to get the type in the type_of
query.
For example consider fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }
.
This is lowered to give HIR something like
type f<‘a>::_Return<’_a> = impl Sized + ’_a; fn f<’a>(x: &’a i32) -> f<’static>::_Return<’a> { x }
When checking the return type record the type from the return and the
type used in the return value. In this case they might be _Return<'1>
and &'2 i32
respectively.
Once we to this method, we have completed region inference and want to
call infer_opaque_definition_from_instantiation
to get the inferred
type of _Return<'_a>
. infer_opaque_definition_from_instantiation
compares lifetimes directly, so we need to map the inference variables
back to concrete lifetimes: 'static
, ReEarlyBound
or ReFree
.
First we map all the lifetimes in the concrete type to an equal
universal region that occurs in the concrete type’s substs, in this case
this would result in &'1 i32
. We only consider regions in the substs
in case there is an equal region that does not. For example, this should
be allowed:
fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }
Then we map the regions in both the type and the subst to their
external_name
giving concrete_type = &'a i32
,
substs = ['static, 'a]
. This will then allow
infer_opaque_definition_from_instantiation
to determine that
_Return<'_a> = &'_a i32
.
There’s a slight complication around closures. Given
fn f<'a: 'a>() { || {} }
the closure’s type is something like
f::<'a>::{{closure}}
. The region parameter from f is essentially
ignored by type checking so ends up being inferred to an empty region.
Calling universal_upper_bound
for such a region gives fr_fn_body
,
which has no external_name
in which case we use 'empty
as the
region to pass to infer_opaque_definition_from_instantiation
.
sourcepub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> Twhere
T: TypeFoldable<'tcx>,
pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> Twhere
T: TypeFoldable<'tcx>,
Map the regions in the type to named regions. This is similar to what
infer_opaque_types
does, but can infer any universal region, not only
ones from the substs for the opaque type. It also doesn’t double check
that the regions produced are in fact equal to the named region they are
replaced with. This is fine because this function is only to improve the
region names in error messages.
sourceimpl RegionInferenceContext<'_>
impl RegionInferenceContext<'_>
sourcepub(super) fn reverse_scc_graph(&mut self) -> Rc<ReverseSccGraph>
pub(super) fn reverse_scc_graph(&mut self) -> Rc<ReverseSccGraph>
Compute and return the reverse SCC-based constraint graph (lazily).
sourceimpl<'tcx> RegionInferenceContext<'tcx>
impl<'tcx> RegionInferenceContext<'tcx>
sourcepub(crate) fn new(
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
outlives_constraints: OutlivesConstraintSet<'tcx>,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
closure_bounds_mapping: FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
universe_causes: FxHashMap<UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>
) -> Self
pub(crate) fn new(
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
outlives_constraints: OutlivesConstraintSet<'tcx>,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
closure_bounds_mapping: FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
universe_causes: FxHashMap<UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>
) -> Self
Creates a new region inference context with a total of
num_region_variables
valid inference variables; the first N
of those will be constant regions representing the free
regions defined in universal_regions
.
The outlives_constraints
and type_tests
are an initial set
of constraints produced by the MIR type check.
sourcefn compute_scc_universes(
constraint_sccs: &Sccs<RegionVid, ConstraintSccIndex>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>
) -> IndexVec<ConstraintSccIndex, UniverseIndex>
fn compute_scc_universes(
constraint_sccs: &Sccs<RegionVid, ConstraintSccIndex>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>
) -> IndexVec<ConstraintSccIndex, UniverseIndex>
Each SCC is the combination of many region variables which have been equated. Therefore, we can associate a universe with each SCC which is minimum of all the universes of its constituent regions – this is because whatever value the SCC takes on must be a value that each of the regions within the SCC could have as well. This implies that the SCC must have the minimum, or narrowest, universe.
sourcefn compute_scc_representatives(
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>
) -> IndexVec<ConstraintSccIndex, RegionVid>
fn compute_scc_representatives(
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>
) -> IndexVec<ConstraintSccIndex, RegionVid>
For each SCC, we compute a unique RegionVid
(in fact, the
minimal one that belongs to the SCC). See
scc_representatives
field of RegionInferenceContext
for
more details.
sourcefn init_free_and_bound_regions(&mut self)
fn init_free_and_bound_regions(&mut self)
Initializes the region variables for each universally quantified region (lifetime parameter). The first N variables always correspond to the regions appearing in the function signature (both named and anonymous) and where-clauses. This function iterates over those regions and initializes them with minimum values.
For example:
fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ }
would initialize two variables like so:
R0 = { CFG, R0 } // 'a
R1 = { CFG, R0, R1 } // 'b
Here, R0 represents 'a
, and it contains (a) the entire CFG
and (b) any universally quantified regions that it outlives,
which in this case is just itself. R1 ('b
) in contrast also
outlives 'a
and hence contains R0 and R1.
sourcepub fn regions(&self) -> impl Iterator<Item = RegionVid> + 'tcx
pub fn regions(&self) -> impl Iterator<Item = RegionVid> + 'tcx
Returns an iterator over all the region indices.
sourcepub fn to_region_vid(&self, r: Region<'tcx>) -> RegionVid
pub fn to_region_vid(&self, r: Region<'tcx>) -> RegionVid
Given a universal region in scope on the MIR, returns the corresponding index.
(Panics if r
is not a registered universal region.)
sourcepub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic)
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic)
Adds annotations for #[rustc_regions]
; see UniversalRegions::annotate
.
sourcepub(crate) fn region_contains(
&self,
r: impl ToRegionVid,
p: impl ToElementIndex
) -> bool
pub(crate) fn region_contains(
&self,
r: impl ToRegionVid,
p: impl ToElementIndex
) -> bool
Returns true
if the region r
contains the point p
.
Panics if called before solve()
executes,
sourcepub(crate) fn region_value_str(&self, r: RegionVid) -> String
pub(crate) fn region_value_str(&self, r: RegionVid) -> String
Returns access to the value of r
for debugging purposes.
sourcepub(crate) fn region_universe(&self, r: RegionVid) -> UniverseIndex
pub(crate) fn region_universe(&self, r: RegionVid) -> UniverseIndex
Returns access to the value of r
for debugging purposes.
sourcepub(crate) fn applied_member_constraints(
&self,
r: impl ToRegionVid
) -> &[AppliedMemberConstraint]
pub(crate) fn applied_member_constraints(
&self,
r: impl ToRegionVid
) -> &[AppliedMemberConstraint]
Once region solving has completed, this function will return
the member constraints that were applied to the value of a given
region r
. See AppliedMemberConstraint
.
sourcepub(crate) fn solve(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
polonius_output: Option<Rc<PoloniusOutput>>
) -> (Option<ClosureRegionRequirements<'tcx>>, Vec<RegionErrorKind<'tcx>>)
pub(crate) fn solve(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
polonius_output: Option<Rc<PoloniusOutput>>
) -> (Option<ClosureRegionRequirements<'tcx>>, Vec<RegionErrorKind<'tcx>>)
Performs region inference and report errors if we see any unsatisfiable constraints. If this is a closure, returns the region requirements to propagate to our creator, if any.
sourcefn propagate_constraints(&mut self, _body: &Body<'tcx>)
fn propagate_constraints(&mut self, _body: &Body<'tcx>)
Propagate the region constraints: this will grow the values for each region variable until all the constraints are satisfied. Note that some values may grow too large to be feasible, but we check this later.
sourcefn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex)
fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex)
Computes the value of the SCC scc_a
, which has not yet been
computed, by unioning the values of its successors.
Assumes that all successors have been computed already
(which is assured by iterating over SCCs in dependency order).
sourcefn apply_member_constraint(
&mut self,
scc: ConstraintSccIndex,
member_constraint_index: NllMemberConstraintIndex,
choice_regions: &[RegionVid]
) -> bool
fn apply_member_constraint(
&mut self,
scc: ConstraintSccIndex,
member_constraint_index: NllMemberConstraintIndex,
choice_regions: &[RegionVid]
) -> bool
Invoked for each R0 member of [R1..Rn]
constraint.
scc
is the SCC containing R0, and choice_regions
are the
R1..Rn
regions – they are always known to be universal
regions (and if that’s not true, we just don’t attempt to
enforce the constraint).
The current value of scc
at the time the method is invoked
is considered a lower bound. If possible, we will modify
the constraint to set it equal to one of the option regions.
If we make any changes, returns true, else false.
sourcefn universe_compatible(
&self,
scc_b: ConstraintSccIndex,
scc_a: ConstraintSccIndex
) -> bool
fn universe_compatible(
&self,
scc_b: ConstraintSccIndex,
scc_a: ConstraintSccIndex
) -> bool
Returns true
if all the elements in the value of scc_b
are nameable
in scc_a
. Used during constraint propagation, and only once
the value of scc_b
has been computed.
sourcefn add_incompatible_universe(&mut self, scc: ConstraintSccIndex)
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex)
Extend scc
so that it can outlive some placeholder region
from a universe it can’t name; at present, the only way for
this to be true is if scc
outlives 'static
. This is
actually stricter than necessary: ideally, we’d support bounds
like for<'a: 'b
>that might then allow us to approximate
’awith
’band not
’static`. But it will have to do for
now.
sourcefn check_type_tests(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
fn check_type_tests(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
Once regions have been propagated, this method is used to see
whether the “type tests” produced by typeck were satisfied;
type tests encode type-outlives relationships like T: 'a
. See TypeTest
for more details.
sourcefn try_promote_type_test(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>
) -> bool
fn try_promote_type_test(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>
) -> bool
Invoked when we have some type-test (e.g., T: 'X
) that we cannot
prove to be satisfied. If this is a closure, we will attempt to
“promote” this type-test into our ClosureRegionRequirements
and
hence pass it up the creator. To do this, we have to phrase the
type-test in terms of external free regions, as local free
regions are not nameable by the closure’s creator.
Promotion works as follows: we first check that the type T
contains only regions that the creator knows about. If this is
true, then – as a consequence – we know that all regions in
the type T
are free regions that outlive the closure body. If
false, then promotion fails.
Once we’ve promoted T, we have to “promote” 'X
to some region
that is “external” to the closure. Generally speaking, a region
may be the union of some points in the closure body as well as
various free lifetimes. We can ignore the points in the closure
body: if the type T can be expressed in terms of external regions,
we know it outlives the points in the closure body. That
just leaves the free regions.
The idea then is to lower the T: 'X
constraint into multiple
bounds – e.g., if 'X
is the union of two free lifetimes,
'1
and '2
, then we would create T: '1
and T: '2
.
sourcefn try_promote_type_test_subject(
&self,
infcx: &InferCtxt<'_, 'tcx>,
ty: Ty<'tcx>
) -> Option<ClosureOutlivesSubject<'tcx>>
fn try_promote_type_test_subject(
&self,
infcx: &InferCtxt<'_, 'tcx>,
ty: Ty<'tcx>
) -> Option<ClosureOutlivesSubject<'tcx>>
When we promote a type test T: 'r
, we have to convert the
type T
into something we can store in a query result (so
something allocated for 'tcx
). This is problematic if ty
contains regions. During the course of NLL region checking, we
will have replaced all of those regions with fresh inference
variables. To create a test subject, we want to replace those
inference variables with some region from the closure
signature – this is not always possible, so this is a
fallible process. Presuming we do find a suitable region, we
will use it’s external name, which will be a RegionKind
variant that can be used in query responses such as
ReEarlyBound
.
sourcefn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid
Given some universal or existential region r
, finds a
non-local, universal region r+
that outlives r
at entry to (and
exit from) the closure. In the worst case, this will be
'static
.
This is used for two purposes. First, if we are propagated
some requirement T: r
, we can use this method to enlarge r
to something we can encode for our creator (which only knows
about non-local, universal regions). It is also used when
encoding T
as part of try_promote_type_test_subject
(see
that fn for details).
This is based on the result 'y
of universal_upper_bound
,
except that it converts further takes the non-local upper
bound of 'y
, so that the final result is non-local.
sourcepub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid
Returns a universally quantified region that outlives the
value of r
(r
may be existentially or universally
quantified).
Since r
is (potentially) an existential region, it has some
value which may include (a) any number of points in the CFG
and (b) any number of end('x)
elements of universally
quantified regions. To convert this into a single universal
region we do as follows:
- Ignore the CFG points in
'r
. All universally quantified regions include the CFG anyhow. - For each
end('x)
element in'r
, compute the mutual LUB, yielding a result'y
.
sourcepub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid
pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid
Like universal_upper_bound
, but returns an approximation more suitable
for diagnostics. If r
contains multiple disjoint universal regions
(e.g. ’a and ’b in fn foo<'a, 'b> { ... }
, we pick the lower-numbered region.
This corresponds to picking named regions over unnamed regions
(e.g. picking early-bound regions over a closure late-bound region).
This means that the returned value may not be a true upper bound, since only ’static is known to outlive disjoint universal regions. Therefore, this method should only be used in diagnostic code, where displaying some named universal region is better than falling back to ’static.
sourcefn eval_verify_bound(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>
) -> bool
fn eval_verify_bound(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>
) -> bool
Tests if test
is true when applied to lower_bound
at
point
.
fn eval_if_eq(
&self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_if_eq_b: Binder<'tcx, VerifyIfEq<'tcx>>
) -> bool
sourcefn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> Twhere
T: TypeFoldable<'tcx>,
fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> Twhere
T: TypeFoldable<'tcx>,
This is a conservative normalization procedure. It takes every
free region in value
and replaces it with the
“representative” of its SCC (see scc_representatives
field).
We are guaranteed that if two values normalize to the same
thing, then they are equal; this is a conservative check in
that they could still be equal even if they normalize to
different results. (For example, there might be two regions
with the same value that are not in the same SCC).
N.B., this is not an ideal approach and I would like to revisit it. However, it works pretty well in practice. In particular, this is needed to deal with projection outlives bounds like
<T as Foo<'0>>::Item: '1
In particular, this routine winds up being important when
there are bounds like where <T as Foo<'a>>::Item: 'b
in the
environment. In this case, if we can show that '0 == 'a
,
and that 'b: '1
, then we know that the clause is
satisfied. In such cases, particularly due to limitations of
the trait solver =), we usually wind up with a where-clause like
T: Foo<'a>
in scope, which thus forces '0 == 'a
to be added as
a constraint, and thus ensures that they are in the same SCC.
So why can’t we do a more correct routine? Well, we could
almost use the relate_tys
code, but the way it is
currently setup it creates inference variables to deal with
higher-ranked things and so forth, and right now the inference
context is not permitted to make more inference variables. So
we use this kind of hacky solution.
fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool
sourcefn check_universal_regions(
&self,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
fn check_universal_regions(
&self,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
Once regions have been propagated, this method is used to see whether any of the constraints were too strong. In particular, we want to check for a case where a universally quantified region exceeded its bounds. Consider:
fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
In this case, returning x
requires &'a u32 <: &'b u32
and hence we establish (transitively) a constraint that
'a: 'b
. The propagate_constraints
code above will
therefore add end('a)
into the region for 'b
– but we
have no evidence that 'b
outlives 'a
, so we want to report
an error.
If propagated_outlives_requirements
is Some
, then we will
push unsatisfied obligations into there. Otherwise, we’ll
report them as errors.
sourcefn check_polonius_subset_errors(
&self,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>,
polonius_output: Rc<PoloniusOutput>
)
fn check_polonius_subset_errors(
&self,
propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>,
polonius_output: Rc<PoloniusOutput>
)
Checks if Polonius has found any unexpected free region relations.
In Polonius terms, a “subset error” (or “illegal subset relation error”) is the equivalent
of NLL’s “checking if any region constraints were too strong”: a placeholder origin 'a
was unexpectedly found to be a subset of another placeholder origin 'b
, and means in NLL
terms that the “longer free region” 'a
outlived the “shorter free region” 'b
.
More details can be found in this blog post by Niko: https://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
In the canonical example
fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
returning x
requires &'a u32 <: &'b u32
and hence we establish (transitively) a
constraint that 'a: 'b
. It is an error that we have no evidence that this
constraint holds.
If propagated_outlives_requirements
is Some
, then we will
push unsatisfied obligations into there. Otherwise, we’ll
report them as errors.
sourcefn check_universal_region(
&self,
longer_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
fn check_universal_region(
&self,
longer_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
Checks the final value for the free region fr
to see if it
grew too large. In particular, examine what end(X)
points
wound up in fr
’s final value; for each end(X)
where X != fr
, we want to check that fr: X
. If not, that’s either an
error, or something we have to propagate to our creator.
Things that are to be propagated are accumulated into the
outlives_requirements
vector.
sourcefn check_universal_region_relation(
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>
) -> RegionRelationCheckResult
fn check_universal_region_relation(
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>
) -> RegionRelationCheckResult
Checks that we can prove that longer_fr: shorter_fr
. If we can’t we attempt to propagate
the constraint outward (e.g. to a closure environment), but if that fails, there is an
error.
sourcefn try_propagate_universal_region_error(
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>
) -> RegionRelationCheckResult
fn try_propagate_universal_region_error(
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>
) -> RegionRelationCheckResult
Attempt to propagate a region error (e.g. 'a: 'b
) that is not met to a closure’s
creator. If we cannot, then the caller should report an error to the user.
fn check_bound_universal_region(
&self,
longer_fr: RegionVid,
placeholder: PlaceholderRegion,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
fn check_member_constraints(
&self,
infcx: &InferCtxt<'_, 'tcx>,
errors_buffer: &mut Vec<RegionErrorKind<'tcx>>
)
sourcepub(crate) fn provides_universal_region(
&self,
r: RegionVid,
fr1: RegionVid,
fr2: RegionVid
) -> bool
pub(crate) fn provides_universal_region(
&self,
r: RegionVid,
fr1: RegionVid,
fr2: RegionVid
) -> bool
We have a constraint fr1: fr2
that is not satisfied, where
fr2
represents some universal region. Here, r
is some
region where we know that fr1: r
and this function has the
job of determining whether r
is “to blame” for the fact that
fr1: fr2
is required.
This is true under two conditions:
r == fr2
fr2
is'static
andr
is some placeholder in a universe that cannot be named byfr1
; in that case, we will require thatfr1: 'static
because it is the only way tofr1: r
to be satisfied. (Seeadd_incompatible_universe
.)
sourcepub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool
pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool
If r2
represents a placeholder region, then this returns
true
if r1
cannot name that placeholder in its
value; otherwise, returns false
.
pub(crate) fn retrieve_closure_constraint_info(
&self,
constraint: OutlivesConstraint<'tcx>
) -> Option<(ConstraintCategory<'tcx>, Span)>
sourcepub(crate) fn find_outlives_blame_span(
&self,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>)
pub(crate) fn find_outlives_blame_span(
&self,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>)
Finds a good ObligationCause
to blame for the fact that fr1
outlives fr2
.
sourcepub(crate) fn find_constraint_paths_between_regions(
&self,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool
) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)>
pub(crate) fn find_constraint_paths_between_regions(
&self,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool
) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)>
Walks the graph of constraints (where 'a: 'b
is considered
an edge 'a -> 'b
) to find all paths from from_region
to
to_region
. The paths are accumulated into the vector
results
. The paths are stored as a series of
ConstraintIndex
values – in other words, a list of edges.
Returns: a series of constraints as well as the region R
that passed the target test.
sourcepub(crate) fn find_sub_region_live_at(
&self,
fr1: RegionVid,
elem: Location
) -> RegionVid
pub(crate) fn find_sub_region_live_at(
&self,
fr1: RegionVid,
elem: Location
) -> RegionVid
Finds some region R such that fr1: R
and R
is live at elem
.
sourcepub(crate) fn region_from_element(
&self,
longer_fr: RegionVid,
element: &RegionElement
) -> RegionVid
pub(crate) fn region_from_element(
&self,
longer_fr: RegionVid,
element: &RegionElement
) -> RegionVid
Get the region outlived by longer_fr
and live at element
.
sourcepub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx>
pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx>
Get the region definition of r
.
sourcepub(crate) fn upper_bound_in_region_scc(
&self,
r: RegionVid,
upper: RegionVid
) -> bool
pub(crate) fn upper_bound_in_region_scc(
&self,
r: RegionVid,
upper: RegionVid
) -> bool
Check if the SCC of r
contains upper
.
pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx>
sourcepub(crate) fn best_blame_constraint(
&self,
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool
) -> BlameConstraint<'tcx>
pub(crate) fn best_blame_constraint(
&self,
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool
) -> BlameConstraint<'tcx>
Tries to find the best constraint to blame for the fact that
R: from_region
, where R
is some region that meets
target_test
. This works by following the constraint graph,
creating a constraint path that forces R
to outlive
from_region
, and then finding the best choices within that
path to blame.
pub(crate) fn universe_info(&self, universe: UniverseIndex) -> UniverseInfo<'tcx>
Auto Trait Implementations
impl<'tcx> !RefUnwindSafe for RegionInferenceContext<'tcx>
impl<'tcx> !Send for RegionInferenceContext<'tcx>
impl<'tcx> !Sync for RegionInferenceContext<'tcx>
impl<'tcx> Unpin for RegionInferenceContext<'tcx>
impl<'tcx> !UnwindSafe for RegionInferenceContext<'tcx>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<'a, T> Captures<'a> for Twhere
T: ?Sized,
Layout
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...)
attributes. Please see the Rust Reference’s “Type Layout” chapter for details on type layout guarantees.
Size: 712 bytes