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