]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_infer/src/infer/outlives/env.rs
47e3dd762b08b2d6f07ce8dd0aa457bfc228ac52
[rustc.git] / compiler / rustc_infer / src / infer / outlives / env.rs
1 use crate::infer::free_regions::FreeRegionMap;
2 use crate::infer::GenericKind;
3 use crate::traits::query::OutlivesBound;
4 use rustc_data_structures::fx::FxIndexSet;
5 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
6 use rustc_middle::ty::{self, Region};
7
8 use super::explicit_outlives_bounds;
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)]
30 pub struct OutlivesEnvironment<'tcx> {
31 pub param_env: ty::ParamEnv<'tcx>,
32 free_region_map: FreeRegionMap<'tcx>,
33
34 // Contains the implied region bounds in scope for our current body.
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 //
44 // Here, when checking the body B0, the list would be `[T: 'a]`, because we
45 // infer that `T` must outlive `'a` from the implied bounds on the
46 // fn declaration.
47 //
48 // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
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.
52 region_bound_pairs: RegionBoundPairs<'tcx>,
53 }
54
55 /// Builder of OutlivesEnvironment.
56 #[derive(Debug)]
57 struct OutlivesEnvironmentBuilder<'tcx> {
58 param_env: ty::ParamEnv<'tcx>,
59 region_relation: TransitiveRelationBuilder<Region<'tcx>>,
60 region_bound_pairs: RegionBoundPairs<'tcx>,
61 }
62
63 /// "Region-bound pairs" tracks outlives relations that are known to
64 /// be true, either because of explicit where-clauses like `T: 'a` or
65 /// because of implied bounds.
66 pub type RegionBoundPairs<'tcx> =
67 FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
68
69 impl<'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 {
73 param_env,
74 region_relation: Default::default(),
75 region_bound_pairs: Default::default(),
76 };
77
78 builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
79
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.
90 pub fn with_bounds(
91 param_env: ty::ParamEnv<'tcx>,
92 extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
93 ) -> Self {
94 let mut builder = Self::builder(param_env);
95 builder.add_outlives_bounds(extra_bounds);
96 builder.build()
97 }
98
99 /// Borrows current value of the `free_region_map`.
100 pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
101 &self.free_region_map
102 }
103
104 /// Borrows current `region_bound_pairs`.
105 pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
106 &self.region_bound_pairs
107 }
108 }
109
110 impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
111 #[inline]
112 #[instrument(level = "debug")]
113 fn build(self) -> OutlivesEnvironment<'tcx> {
114 OutlivesEnvironment {
115 param_env: self.param_env,
116 free_region_map: FreeRegionMap { relation: self.region_relation.freeze() },
117 region_bound_pairs: self.region_bound_pairs,
118 }
119 }
120
121 /// Processes outlives bounds that are known to hold, whether from implied or other sources.
122 fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
123 where
124 I: IntoIterator<Item = OutlivesBound<'tcx>>,
125 {
126 // Record relationships such as `T:'x` that don't go into the
127 // free-region-map but which we use here.
128 for outlives_bound in outlives_bounds {
129 debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
130 match outlives_bound {
131 OutlivesBound::RegionSubParam(r_a, param_b) => {
132 self.region_bound_pairs
133 .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
134 }
135 OutlivesBound::RegionSubAlias(r_a, alias_b) => {
136 self.region_bound_pairs
137 .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
138 }
139 OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
140 (
141 ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
142 ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
143 ) => self.region_relation.add(r_a, r_b),
144 (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
145 // FIXME(#109628): We shouldn't have existential variables in implied bounds.
146 // Panic here once the linked issue is resolved!
147 (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
148 _ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
149 },
150 }
151 }
152 }
153 }