]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/region_infer/opaque_types.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / region_infer / opaque_types.rs
CommitLineData
c295e0f8 1use rustc_data_structures::fx::FxHashMap;
17df50a5 2use rustc_data_structures::vec_map::VecMap;
c295e0f8
XL
3use rustc_hir::OpaqueTyOrigin;
4use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
74b04a01 5use rustc_infer::infer::InferCtxt;
c295e0f8 6use rustc_middle::ty::subst::GenericArgKind;
17df50a5 7use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
74b04a01 8use rustc_span::Span;
ba9703b0 9use rustc_trait_selection::opaque_types::InferCtxtExt;
74b04a01
XL
10
11use super::RegionInferenceContext;
12
13impl<'tcx> RegionInferenceContext<'tcx> {
14 /// Resolve any opaque types that were encountered while borrow checking
15 /// this item. This is then used to get the type in the `type_of` query.
16 ///
17 /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
18 /// This is lowered to give HIR something like
19 ///
20 /// type f<'a>::_Return<'_a> = impl Sized + '_a;
21 /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
22 ///
23 /// When checking the return type record the type from the return and the
24 /// type used in the return value. In this case they might be `_Return<'1>`
25 /// and `&'2 i32` respectively.
26 ///
27 /// Once we to this method, we have completed region inference and want to
28 /// call `infer_opaque_definition_from_instantiation` to get the inferred
29 /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
30 /// compares lifetimes directly, so we need to map the inference variables
31 /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
32 ///
33 /// First we map all the lifetimes in the concrete type to an equal
34 /// universal region that occurs in the concrete type's substs, in this case
35 /// this would result in `&'1 i32`. We only consider regions in the substs
36 /// in case there is an equal region that does not. For example, this should
37 /// be allowed:
38 /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
39 ///
40 /// Then we map the regions in both the type and the subst to their
41 /// `external_name` giving `concrete_type = &'a i32`,
42 /// `substs = ['static, 'a]`. This will then allow
43 /// `infer_opaque_definition_from_instantiation` to determine that
44 /// `_Return<'_a> = &'_a i32`.
45 ///
46 /// There's a slight complication around closures. Given
47 /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
48 /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
49 /// ignored by type checking so ends up being inferred to an empty region.
50 /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
51 /// which has no `external_name` in which case we use `'empty` as the
52 /// region to pass to `infer_opaque_definition_from_instantiation`.
c295e0f8
XL
53 #[instrument(level = "debug", skip(self, infcx))]
54 pub(crate) fn infer_opaque_types(
74b04a01
XL
55 &self,
56 infcx: &InferCtxt<'_, 'tcx>,
c295e0f8 57 opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
74b04a01 58 span: Span,
17df50a5 59 ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
74b04a01
XL
60 opaque_ty_decls
61 .into_iter()
c295e0f8 62 .filter_map(|(opaque_type_key, decl)| {
17df50a5 63 let substs = opaque_type_key.substs;
c295e0f8 64 let concrete_type = decl.concrete_ty;
6a06907d 65 debug!(?concrete_type, ?substs);
74b04a01
XL
66
67 let mut subst_regions = vec![self.universal_regions.fr_static];
136023e0
XL
68 let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
69 let vid = self.universal_regions.to_region_vid(region);
70 subst_regions.push(vid);
71 self.definitions[vid].external_name.unwrap_or_else(|| {
72 infcx
73 .tcx
74 .sess
75 .delay_span_bug(span, "opaque type with non-universal region substs");
76 infcx.tcx.lifetimes.re_static
77 })
78 });
74b04a01
XL
79
80 subst_regions.sort();
81 subst_regions.dedup();
82
83 let universal_concrete_type =
fc512014 84 infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
74b04a01
XL
85 ty::ReVar(vid) => subst_regions
86 .iter()
87 .find(|ur_vid| self.eval_equal(vid, **ur_vid))
88 .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
89 .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
136023e0 90 _ => region,
74b04a01
XL
91 });
92
6a06907d 93 debug!(?universal_concrete_type, ?universal_substs);
74b04a01 94
17df50a5
XL
95 let opaque_type_key =
96 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
74b04a01 97 let remapped_type = infcx.infer_opaque_definition_from_instantiation(
17df50a5 98 opaque_type_key,
74b04a01
XL
99 universal_concrete_type,
100 span,
101 );
c295e0f8
XL
102
103 check_opaque_type_parameter_valid(
104 infcx.tcx,
105 opaque_type_key,
106 OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
107 )
108 .then_some((opaque_type_key, remapped_type))
74b04a01
XL
109 })
110 .collect()
111 }
112
113 /// Map the regions in the type to named regions. This is similar to what
114 /// `infer_opaque_types` does, but can infer any universal region, not only
115 /// ones from the substs for the opaque type. It also doesn't double check
116 /// that the regions produced are in fact equal to the named region they are
117 /// replaced with. This is fine because this function is only to improve the
118 /// region names in error messages.
c295e0f8 119 pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
74b04a01
XL
120 where
121 T: TypeFoldable<'tcx>,
122 {
fc512014 123 tcx.fold_regions(ty, &mut false, |region, _| match *region {
74b04a01 124 ty::ReVar(vid) => {
f035d41b
XL
125 // Find something that we can name
126 let upper_bound = self.approx_universal_upper_bound(vid);
c295e0f8
XL
127 let upper_bound = &self.definitions[upper_bound];
128 match upper_bound.external_name {
129 Some(reg) => reg,
130 None => {
131 // Nothing exact found, so we pick the first one that we find.
132 let scc = self.constraint_sccs.scc(vid);
133 for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
134 match self.definitions[vid].external_name {
135 None => {}
136 Some(&ty::ReStatic) => {}
137 Some(region) => return region,
138 }
139 }
140 region
141 }
142 }
74b04a01
XL
143 }
144 _ => region,
145 })
146 }
147}
c295e0f8
XL
148
149fn check_opaque_type_parameter_valid(
150 tcx: TyCtxt<'_>,
151 opaque_type_key: OpaqueTypeKey<'_>,
152 decl: OpaqueTypeDecl<'_>,
153) -> bool {
154 match decl.origin {
155 // No need to check return position impl trait (RPIT)
156 // because for type and const parameters they are correct
157 // by construction: we convert
158 //
159 // fn foo<P0..Pn>() -> impl Trait
160 //
161 // into
162 //
163 // type Foo<P0...Pn>
164 // fn foo<P0..Pn>() -> Foo<P0...Pn>.
165 //
166 // For lifetime parameters we convert
167 //
168 // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
169 //
170 // into
171 //
172 // type foo::<'p0..'pn>::Foo<'q0..'qm>
173 // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
174 //
175 // which would error here on all of the `'static` args.
a2a8927a 176 OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
c295e0f8
XL
177 // Check these
178 OpaqueTyOrigin::TyAlias => {}
179 }
180 let span = decl.definition_span;
181 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
182 let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
183 for (i, arg) in opaque_type_key.substs.iter().enumerate() {
184 let arg_is_param = match arg.unpack() {
185 GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
186 GenericArgKind::Lifetime(ty::ReStatic) => {
187 tcx.sess
188 .struct_span_err(span, "non-defining opaque type use in defining scope")
189 .span_label(
190 tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
191 "cannot use static lifetime; use a bound lifetime \
192 instead or remove the lifetime parameter from the \
193 opaque type",
194 )
195 .emit();
196 return false;
197 }
198 GenericArgKind::Lifetime(lt) => {
199 matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
200 }
201 GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
202 };
203
204 if arg_is_param {
205 seen_params.entry(arg).or_default().push(i);
206 } else {
207 // Prevent `fn foo() -> Foo<u32>` from being defining.
208 let opaque_param = opaque_generics.param_at(i, tcx);
209 tcx.sess
210 .struct_span_err(span, "non-defining opaque type use in defining scope")
211 .span_note(
212 tcx.def_span(opaque_param.def_id),
213 &format!(
214 "used non-generic {} `{}` for generic parameter",
215 opaque_param.kind.descr(),
216 arg,
217 ),
218 )
219 .emit();
220 return false;
221 }
222 }
223
224 for (_, indices) in seen_params {
225 if indices.len() > 1 {
226 let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
227 let spans: Vec<_> = indices
228 .into_iter()
229 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
230 .collect();
231 tcx.sess
232 .struct_span_err(span, "non-defining opaque type use in defining scope")
233 .span_note(spans, &format!("{} used multiple times", descr))
234 .emit();
235 return false;
236 }
237 }
238 true
239}