]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/outlives/env.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / outlives / env.rs
CommitLineData
f9f354fc 1use crate::infer::free_regions::FreeRegionMap;
9fa01778 2use crate::infer::{GenericKind, InferCtxt};
ba9703b0 3use crate::traits::query::OutlivesBound;
064997fb 4use rustc_data_structures::fx::FxIndexSet;
f2b60f7d 5use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
5099ac24 6use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
ba9703b0
XL
7
8use super::explicit_outlives_bounds;
abe05a73
XL
9
10/// The `OutlivesEnvironment` collects information about what outlives
11/// what in a given type-checking setting. For example, if we have a
12/// where-clause like `where T: 'a` in scope, then the
13/// `OutlivesEnvironment` would record that (in its
14/// `region_bound_pairs` field). Similarly, it contains methods for
15/// processing and adding implied bounds into the outlives
16/// environment.
17///
18/// Other code at present does not typically take a
19/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
20/// `process_registered_region_obligations` wants the
21/// region-bound-pairs). There is no mistaking it: the current setup
22/// of tracking region information is quite scattered! The
23/// `OutlivesEnvironment`, for example, needs to sometimes be combined
24/// with the `middle::RegionRelations`, to yield a full picture of how
25/// (lexical) lifetimes interact. However, I'm reluctant to do more
26/// refactoring here, since the setup with NLL is quite different.
27/// For example, NLL has no need of `RegionRelations`, and is solely
28/// interested in the `OutlivesEnvironment`. -nmatsakis
29#[derive(Clone)]
30pub struct OutlivesEnvironment<'tcx> {
416331ca 31 pub param_env: ty::ParamEnv<'tcx>,
abe05a73 32 free_region_map: FreeRegionMap<'tcx>,
0bf4aa26 33
064997fb 34 // Contains the implied region bounds in scope for our current body.
0bf4aa26
XL
35 //
36 // Example:
37 //
38 // ```
39 // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
40 // bar(x, y, |y: &'b T| { .. } // body B1)
41 // } // body B0
42 // ```
43 //
064997fb 44 // Here, when checking the body B0, the list would be `[T: 'a]`, because we
0bf4aa26
XL
45 // infer that `T` must outlive `'a` from the implied bounds on the
46 // fn declaration.
47 //
064997fb 48 // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
0bf4aa26
XL
49 // also can see that -- within the closure body! -- `T` must
50 // outlive `'b`. This is not necessarily true outside the closure
51 // body, since the closure may never be called.
064997fb 52 region_bound_pairs: RegionBoundPairs<'tcx>,
abe05a73
XL
53}
54
f2b60f7d
FG
55/// Builder of OutlivesEnvironment.
56#[derive(Debug)]
57struct OutlivesEnvironmentBuilder<'tcx> {
58 param_env: ty::ParamEnv<'tcx>,
59 region_relation: TransitiveRelationBuilder<Region<'tcx>>,
60 region_bound_pairs: RegionBoundPairs<'tcx>,
61}
62
0bf4aa26 63/// "Region-bound pairs" tracks outlives relations that are known to
9fa01778 64/// be true, either because of explicit where-clauses like `T: 'a` or
0bf4aa26 65/// because of implied bounds.
064997fb
FG
66pub type RegionBoundPairs<'tcx> =
67 FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
0bf4aa26 68
f2b60f7d
FG
69impl<'tcx> OutlivesEnvironment<'tcx> {
70 /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
71 fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> {
72 let mut builder = OutlivesEnvironmentBuilder {
abe05a73 73 param_env,
f2b60f7d 74 region_relation: Default::default(),
064997fb 75 region_bound_pairs: Default::default(),
ff7c6d11
XL
76 };
77
f2b60f7d 78 builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
ff7c6d11 79
f2b60f7d
FG
80 builder
81 }
82
83 #[inline]
84 /// Create a new `OutlivesEnvironment` without extra outlives bounds.
85 pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
86 Self::builder(param_env).build()
87 }
88
89 /// Create a new `OutlivesEnvironment` with extra outlives bounds.
2b03887a 90 pub fn with_bounds(
f2b60f7d 91 param_env: ty::ParamEnv<'tcx>,
2b03887a 92 infcx: Option<&InferCtxt<'tcx>>,
f2b60f7d
FG
93 extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
94 ) -> Self {
95 let mut builder = Self::builder(param_env);
96 builder.add_outlives_bounds(infcx, extra_bounds);
97 builder.build()
abe05a73
XL
98 }
99
100 /// Borrows current value of the `free_region_map`.
101 pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
102 &self.free_region_map
103 }
104
064997fb
FG
105 /// Borrows current `region_bound_pairs`.
106 pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
107 &self.region_bound_pairs
0bf4aa26 108 }
f2b60f7d
FG
109}
110
2b03887a 111impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
f2b60f7d
FG
112 #[inline]
113 #[instrument(level = "debug")]
114 fn build(self) -> OutlivesEnvironment<'tcx> {
115 OutlivesEnvironment {
116 param_env: self.param_env,
117 free_region_map: FreeRegionMap { relation: self.region_relation.freeze() },
118 region_bound_pairs: self.region_bound_pairs,
119 }
120 }
0bf4aa26 121
ff7c6d11
XL
122 /// Processes outlives bounds that are known to hold, whether from implied or other sources.
123 ///
124 /// The `infcx` parameter is optional; if the implied bounds may
125 /// contain inference variables, it must be supplied, in which
126 /// case we will register "givens" on the inference context. (See
127 /// `RegionConstraintData`.)
2b03887a 128 fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
f2b60f7d 129 where
ff7c6d11
XL
130 I: IntoIterator<Item = OutlivesBound<'tcx>>,
131 {
132 // Record relationships such as `T:'x` that don't go into the
133 // free-region-map but which we use here.
134 for outlives_bound in outlives_bounds {
135 debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
136 match outlives_bound {
ff7c6d11 137 OutlivesBound::RegionSubParam(r_a, param_b) => {
064997fb
FG
138 self.region_bound_pairs
139 .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
abe05a73 140 }
f25598a0 141 OutlivesBound::RegionSubAlias(r_a, alias_b) => {
064997fb 142 self.region_bound_pairs
f25598a0 143 .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
2b03887a 144 }
ff7c6d11 145 OutlivesBound::RegionSubRegion(r_a, r_b) => {
04454e1e
FG
146 if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
147 infcx
148 .expect("no infcx provided but region vars found")
149 .add_given(r_a, vid_b);
150 } else {
151 // In principle, we could record (and take
152 // advantage of) every relationship here, but
153 // we are also free not to -- it simply means
154 // strictly less that we can successfully type
155 // check. Right now we only look for things
156 // relationships between free regions. (It may
157 // also be that we should revise our inference
158 // system to be more general and to make use
159 // of *every* relationship that arises here,
160 // but presently we do not.)
f2b60f7d
FG
161 if r_a.is_free_or_static() && r_b.is_free() {
162 self.region_relation.add(r_a, r_b)
163 }
04454e1e 164 }
ff7c6d11
XL
165 }
166 }
167 }
abe05a73
XL
168 }
169}