1use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
2use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
3use rustc_middle::{bug, ty};
4use tracing::debug;
56use super::explicit_outlives_bounds;
7use crate::infer::GenericKind;
8use crate::infer::free_regions::FreeRegionMap;
9use crate::traits::query::OutlivesBound;
1011/// The `OutlivesEnvironment` collects information about what outlives
12/// what in a given type-checking setting. For example, if we have a
13/// where-clause like `where T: 'a` in scope, then the
14/// `OutlivesEnvironment` would record that (in its
15/// `region_bound_pairs` field). Similarly, it contains methods for
16/// processing and adding implied bounds into the outlives
17/// environment.
18///
19/// Other code at present does not typically take a
20/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
21/// `process_registered_region_obligations` wants the
22/// region-bound-pairs). There is no mistaking it: the current setup
23/// of tracking region information is quite scattered! The
24/// `OutlivesEnvironment`, for example, needs to sometimes be combined
25/// with the `middle::RegionRelations`, to yield a full picture of how
26/// (lexical) lifetimes interact. However, I'm reluctant to do more
27/// refactoring here, since the setup with NLL is quite different.
28/// For example, NLL has no need of `RegionRelations`, and is solely
29/// interested in the `OutlivesEnvironment`. -nmatsakis
30#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for OutlivesEnvironment<'tcx> {
#[inline]
fn clone(&self) -> OutlivesEnvironment<'tcx> {
OutlivesEnvironment {
param_env: ::core::clone::Clone::clone(&self.param_env),
free_region_map: ::core::clone::Clone::clone(&self.free_region_map),
region_bound_pairs: ::core::clone::Clone::clone(&self.region_bound_pairs),
known_type_outlives: ::core::clone::Clone::clone(&self.known_type_outlives),
higher_ranked_assumptions: ::core::clone::Clone::clone(&self.higher_ranked_assumptions),
}
}
}Clone)]
31pub struct OutlivesEnvironment<'tcx> {
32pub param_env: ty::ParamEnv<'tcx>,
33 free_region_map: FreeRegionMap<'tcx>,
34/// FIXME: Your first reaction may be that this is a bit strange. `RegionBoundPairs`
35 /// does not contain lifetimes, which are instead in the `FreeRegionMap`, and other
36 /// known type outlives are stored in the `known_type_outlives` set. So why do we
37 /// have these at all? It turns out that removing these and using `known_type_outlives`
38 /// everywhere is just enough of a perf regression to matter. This can/should be
39 /// optimized in the future, though.
40region_bound_pairs: RegionBoundPairs<'tcx>,
41 known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
42/// Assumptions that come from the well-formedness of coroutines that we prove
43 /// auto trait bounds for during the type checking of this body.
44higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
45}
4647/// "Region-bound pairs" tracks outlives relations that are known to
48/// be true, either because of explicit where-clauses like `T: 'a` or
49/// because of implied bounds.
50pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
5152impl<'tcx> OutlivesEnvironment<'tcx> {
53/// Create a new `OutlivesEnvironment` from normalized outlives bounds.
54pub fn from_normalized_bounds(
55 param_env: ty::ParamEnv<'tcx>,
56 known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
57 extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
58 higher_ranked_assumptions: FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
59 ) -> Self {
60let mut region_relation = TransitiveRelationBuilder::default();
61let mut region_bound_pairs = RegionBoundPairs::default();
6263// Record relationships such as `T:'x` that don't go into the
64 // free-region-map but which we use here.
65for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) {
66{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/outlives/env.rs:66",
"rustc_infer::infer::outlives::env",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/outlives/env.rs"),
::tracing_core::__macro_support::Option::Some(66u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::outlives::env"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("add_outlives_bounds: outlives_bound={0:?}",
outlives_bound) as &dyn Value))])
});
} else { ; }
};debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
67match outlives_bound {
68 OutlivesBound::RegionSubParam(r_a, param_b) => {
69 region_bound_pairs
70 .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
71 }
72 OutlivesBound::RegionSubAlias(r_a, alias_b) => {
73 region_bound_pairs
74 .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
75 }
76 OutlivesBound::RegionSubRegion(r_a, r_b) => match (r_a.kind(), r_b.kind()) {
77 (
78 ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
79 ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
80 ) => region_relation.add(r_a, r_b),
81 (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
82// FIXME(#109628): We shouldn't have existential variables in implied bounds.
83 // Panic here once the linked issue is resolved!
84(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
85_ => ::rustc_middle::util::bug::bug_fmt(format_args!("add_outlives_bounds: unexpected regions: ({0:?}, {1:?})",
r_a, r_b))bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
86 },
87 }
88 }
8990OutlivesEnvironment {
91param_env,
92known_type_outlives,
93 free_region_map: FreeRegionMap { relation: region_relation.freeze() },
94region_bound_pairs,
95higher_ranked_assumptions,
96 }
97 }
9899pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
100&self.free_region_map
101 }
102103pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
104&self.region_bound_pairs
105 }
106107pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
108&self.known_type_outlives
109 }
110111pub fn higher_ranked_assumptions(&self) -> &FxHashSet<ty::ArgOutlivesPredicate<'tcx>> {
112&self.higher_ranked_assumptions
113 }
114}