]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/outlives/env.rs
Rollup merge of #99110 - audunhalland:match_has_guard_from_candidate, r=pnkfelix
[rust.git] / compiler / rustc_infer / src / infer / outlives / env.rs
1 use crate::infer::free_regions::FreeRegionMap;
2 use crate::infer::{GenericKind, InferCtxt};
3 use crate::traits::query::OutlivesBound;
4 use rustc_data_structures::fx::FxIndexSet;
5 use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
6
7 use super::explicit_outlives_bounds;
8
9 /// The `OutlivesEnvironment` collects information about what outlives
10 /// what in a given type-checking setting. For example, if we have a
11 /// where-clause like `where T: 'a` in scope, then the
12 /// `OutlivesEnvironment` would record that (in its
13 /// `region_bound_pairs` field). Similarly, it contains methods for
14 /// processing and adding implied bounds into the outlives
15 /// environment.
16 ///
17 /// Other code at present does not typically take a
18 /// `&OutlivesEnvironment`, but rather takes some of its fields (e.g.,
19 /// `process_registered_region_obligations` wants the
20 /// region-bound-pairs). There is no mistaking it: the current setup
21 /// of tracking region information is quite scattered! The
22 /// `OutlivesEnvironment`, for example, needs to sometimes be combined
23 /// with the `middle::RegionRelations`, to yield a full picture of how
24 /// (lexical) lifetimes interact. However, I'm reluctant to do more
25 /// refactoring here, since the setup with NLL is quite different.
26 /// For example, NLL has no need of `RegionRelations`, and is solely
27 /// interested in the `OutlivesEnvironment`. -nmatsakis
28 #[derive(Clone)]
29 pub struct OutlivesEnvironment<'tcx> {
30     pub param_env: ty::ParamEnv<'tcx>,
31     free_region_map: FreeRegionMap<'tcx>,
32
33     // Contains the implied region bounds in scope for our current body.
34     //
35     // Example:
36     //
37     // ```
38     // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
39     //   bar(x, y, |y: &'b T| { .. } // body B1)
40     // } // body B0
41     // ```
42     //
43     // Here, when checking the body B0, the list would be `[T: 'a]`, because we
44     // infer that `T` must outlive `'a` from the implied bounds on the
45     // fn declaration.
46     //
47     // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
48     // also can see that -- within the closure body! -- `T` must
49     // outlive `'b`. This is not necessarily true outside the closure
50     // body, since the closure may never be called.
51     region_bound_pairs: RegionBoundPairs<'tcx>,
52 }
53
54 /// "Region-bound pairs" tracks outlives relations that are known to
55 /// be true, either because of explicit where-clauses like `T: 'a` or
56 /// because of implied bounds.
57 pub type RegionBoundPairs<'tcx> =
58     FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
59
60 impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
61     pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
62         let mut env = OutlivesEnvironment {
63             param_env,
64             free_region_map: Default::default(),
65             region_bound_pairs: Default::default(),
66         };
67
68         env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
69
70         env
71     }
72
73     /// Borrows current value of the `free_region_map`.
74     pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
75         &self.free_region_map
76     }
77
78     /// Borrows current `region_bound_pairs`.
79     pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
80         &self.region_bound_pairs
81     }
82
83     /// Processes outlives bounds that are known to hold, whether from implied or other sources.
84     ///
85     /// The `infcx` parameter is optional; if the implied bounds may
86     /// contain inference variables, it must be supplied, in which
87     /// case we will register "givens" on the inference context. (See
88     /// `RegionConstraintData`.)
89     pub fn add_outlives_bounds<I>(
90         &mut self,
91         infcx: Option<&InferCtxt<'a, 'tcx>>,
92         outlives_bounds: I,
93     ) where
94         I: IntoIterator<Item = OutlivesBound<'tcx>>,
95     {
96         // Record relationships such as `T:'x` that don't go into the
97         // free-region-map but which we use here.
98         for outlives_bound in outlives_bounds {
99             debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
100             match outlives_bound {
101                 OutlivesBound::RegionSubParam(r_a, param_b) => {
102                     self.region_bound_pairs
103                         .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
104                 }
105                 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
106                     self.region_bound_pairs
107                         .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
108                 }
109                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
110                     if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
111                         infcx
112                             .expect("no infcx provided but region vars found")
113                             .add_given(r_a, vid_b);
114                     } else {
115                         // In principle, we could record (and take
116                         // advantage of) every relationship here, but
117                         // we are also free not to -- it simply means
118                         // strictly less that we can successfully type
119                         // check. Right now we only look for things
120                         // relationships between free regions. (It may
121                         // also be that we should revise our inference
122                         // system to be more general and to make use
123                         // of *every* relationship that arises here,
124                         // but presently we do not.)
125                         self.free_region_map.relate_regions(r_a, r_b);
126                     }
127                 }
128             }
129         }
130     }
131 }