]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
Mir borrowck does not generate lifetime variables for 'static lifetimes during opaque...
[rust.git] / compiler / rustc_mir / src / borrow_check / region_infer / opaque_types.rs
1 use rustc_data_structures::vec_map::VecMap;
2 use rustc_infer::infer::InferCtxt;
3 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
4 use rustc_span::Span;
5 use rustc_trait_selection::opaque_types::InferCtxtExt;
6
7 use super::RegionInferenceContext;
8
9 impl<'tcx> RegionInferenceContext<'tcx> {
10     /// Resolve any opaque types that were encountered while borrow checking
11     /// this item. This is then used to get the type in the `type_of` query.
12     ///
13     /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
14     /// This is lowered to give HIR something like
15     ///
16     /// type f<'a>::_Return<'_a> = impl Sized + '_a;
17     /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
18     ///
19     /// When checking the return type record the type from the return and the
20     /// type used in the return value. In this case they might be `_Return<'1>`
21     /// and `&'2 i32` respectively.
22     ///
23     /// Once we to this method, we have completed region inference and want to
24     /// call `infer_opaque_definition_from_instantiation` to get the inferred
25     /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
26     /// compares lifetimes directly, so we need to map the inference variables
27     /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
28     ///
29     /// First we map all the lifetimes in the concrete type to an equal
30     /// universal region that occurs in the concrete type's substs, in this case
31     /// this would result in `&'1 i32`. We only consider regions in the substs
32     /// in case there is an equal region that does not. For example, this should
33     /// be allowed:
34     /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
35     ///
36     /// Then we map the regions in both the type and the subst to their
37     /// `external_name` giving `concrete_type = &'a i32`,
38     /// `substs = ['static, 'a]`. This will then allow
39     /// `infer_opaque_definition_from_instantiation` to determine that
40     /// `_Return<'_a> = &'_a i32`.
41     ///
42     /// There's a slight complication around closures. Given
43     /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
44     /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
45     /// ignored by type checking so ends up being inferred to an empty region.
46     /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
47     /// which has no `external_name` in which case we use `'empty` as the
48     /// region to pass to `infer_opaque_definition_from_instantiation`.
49     #[instrument(skip(self, infcx))]
50     pub(in crate::borrow_check) fn infer_opaque_types(
51         &self,
52         infcx: &InferCtxt<'_, 'tcx>,
53         opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
54         span: Span,
55     ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
56         opaque_ty_decls
57             .into_iter()
58             .map(|(opaque_type_key, concrete_type)| {
59                 let substs = opaque_type_key.substs;
60                 debug!(?concrete_type, ?substs);
61
62                 let mut subst_regions = vec![self.universal_regions.fr_static];
63                 let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
64                     let vid = self.universal_regions.to_region_vid(region);
65                     subst_regions.push(vid);
66                     self.definitions[vid].external_name.unwrap_or_else(|| {
67                         infcx
68                             .tcx
69                             .sess
70                             .delay_span_bug(span, "opaque type with non-universal region substs");
71                         infcx.tcx.lifetimes.re_static
72                     })
73                 });
74
75                 subst_regions.sort();
76                 subst_regions.dedup();
77
78                 let universal_concrete_type =
79                     infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
80                         ty::ReVar(vid) => subst_regions
81                             .iter()
82                             .find(|ur_vid| self.eval_equal(vid, **ur_vid))
83                             .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
84                             .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
85                         ty::ReLateBound(..) => region,
86                         ty::ReStatic => region,
87                         _ => {
88                             infcx.tcx.sess.delay_span_bug(
89                                 span,
90                                 &format!("unexpected concrete region in borrowck: {:?}", region),
91                             );
92                             region
93                         }
94                     });
95
96                 debug!(?universal_concrete_type, ?universal_substs);
97
98                 let opaque_type_key =
99                     OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
100                 let remapped_type = infcx.infer_opaque_definition_from_instantiation(
101                     opaque_type_key,
102                     universal_concrete_type,
103                     span,
104                 );
105                 (opaque_type_key, remapped_type)
106             })
107             .collect()
108     }
109
110     /// Map the regions in the type to named regions. This is similar to what
111     /// `infer_opaque_types` does, but can infer any universal region, not only
112     /// ones from the substs for the opaque type. It also doesn't double check
113     /// that the regions produced are in fact equal to the named region they are
114     /// replaced with. This is fine because this function is only to improve the
115     /// region names in error messages.
116     pub(in crate::borrow_check) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
117     where
118         T: TypeFoldable<'tcx>,
119     {
120         tcx.fold_regions(ty, &mut false, |region, _| match *region {
121             ty::ReVar(vid) => {
122                 // Find something that we can name
123                 let upper_bound = self.approx_universal_upper_bound(vid);
124                 self.definitions[upper_bound].external_name.unwrap_or(region)
125             }
126             _ => region,
127         })
128     }
129 }