rustc_borrowck/type_check/opaque_types.rs
1use std::iter;
2
3use rustc_data_structures::fx::FxIndexMap;
4use rustc_middle::span_bug;
5use rustc_middle::ty::{
6 self, GenericArgKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeSuperVisitable,
7 TypeVisitable, TypeVisitableExt, TypeVisitor, fold_regions,
8};
9use tracing::{debug, trace};
10
11use super::{MemberConstraintSet, TypeChecker};
12
13/// Once we're done with typechecking the body, we take all the opaque types
14/// defined by this function and add their 'member constraints'.
15pub(super) fn take_opaques_and_register_member_constraints<'tcx>(
16 typeck: &mut TypeChecker<'_, 'tcx>,
17) -> FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>> {
18 let infcx = typeck.infcx;
19 // Annoying: to invoke `typeck.to_region_vid`, we need access to
20 // `typeck.constraints`, but we also want to be mutating
21 // `typeck.member_constraints`. For now, just swap out the value
22 // we want and replace at the end.
23 let mut member_constraints = std::mem::take(&mut typeck.constraints.member_constraints);
24 let opaque_types = infcx
25 .take_opaque_types()
26 .into_iter()
27 .map(|(opaque_type_key, hidden_type)| {
28 let hidden_type = infcx.resolve_vars_if_possible(hidden_type);
29 register_member_constraints(
30 typeck,
31 &mut member_constraints,
32 opaque_type_key,
33 hidden_type,
34 );
35 trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
36 if hidden_type.has_non_region_infer() {
37 span_bug!(hidden_type.span, "could not resolve {:?}", hidden_type.ty);
38 }
39
40 // Convert all regions to nll vars.
41 let (opaque_type_key, hidden_type) =
42 fold_regions(infcx.tcx, (opaque_type_key, hidden_type), |r, _| {
43 ty::Region::new_var(infcx.tcx, typeck.to_region_vid(r))
44 });
45
46 (opaque_type_key, hidden_type)
47 })
48 .collect();
49 assert!(typeck.constraints.member_constraints.is_empty());
50 typeck.constraints.member_constraints = member_constraints;
51 opaque_types
52}
53
54/// Given the map `opaque_types` containing the opaque
55/// `impl Trait` types whose underlying, hidden types are being
56/// inferred, this method adds constraints to the regions
57/// appearing in those underlying hidden types to ensure that they
58/// at least do not refer to random scopes within the current
59/// function. These constraints are not (quite) sufficient to
60/// guarantee that the regions are actually legal values; that
61/// final condition is imposed after region inference is done.
62///
63/// # The Problem
64///
65/// Let's work through an example to explain how it works. Assume
66/// the current function is as follows:
67///
68/// ```text
69/// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
70/// ```
71///
72/// Here, we have two `impl Trait` types whose values are being
73/// inferred (the `impl Bar<'a>` and the `impl
74/// Bar<'b>`). Conceptually, this is sugar for a setup where we
75/// define underlying opaque types (`Foo1`, `Foo2`) and then, in
76/// the return type of `foo`, we *reference* those definitions:
77///
78/// ```text
79/// type Foo1<'x> = impl Bar<'x>;
80/// type Foo2<'x> = impl Bar<'x>;
81/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
82/// // ^^^^ ^^
83/// // | |
84/// // | args
85/// // def_id
86/// ```
87///
88/// As indicating in the comments above, each of those references
89/// is (in the compiler) basically generic parameters (`args`)
90/// applied to the type of a suitable `def_id` (which identifies
91/// `Foo1` or `Foo2`).
92///
93/// Now, at this point in compilation, what we have done is to
94/// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
95/// fresh inference variables C1 and C2. We wish to use the values
96/// of these variables to infer the underlying types of `Foo1` and
97/// `Foo2`. That is, this gives rise to higher-order (pattern) unification
98/// constraints like:
99///
100/// ```text
101/// for<'a> (Foo1<'a> = C1)
102/// for<'b> (Foo1<'b> = C2)
103/// ```
104///
105/// For these equation to be satisfiable, the types `C1` and `C2`
106/// can only refer to a limited set of regions. For example, `C1`
107/// can only refer to `'static` and `'a`, and `C2` can only refer
108/// to `'static` and `'b`. The job of this function is to impose that
109/// constraint.
110///
111/// Up to this point, C1 and C2 are basically just random type
112/// inference variables, and hence they may contain arbitrary
113/// regions. In fact, it is fairly likely that they do! Consider
114/// this possible definition of `foo`:
115///
116/// ```text
117/// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
118/// (&*x, &*y)
119/// }
120/// ```
121///
122/// Here, the values for the concrete types of the two impl
123/// traits will include inference variables:
124///
125/// ```text
126/// &'0 i32
127/// &'1 i32
128/// ```
129///
130/// Ordinarily, the subtyping rules would ensure that these are
131/// sufficiently large. But since `impl Bar<'a>` isn't a specific
132/// type per se, we don't get such constraints by default. This
133/// is where this function comes into play. It adds extra
134/// constraints to ensure that all the regions which appear in the
135/// inferred type are regions that could validly appear.
136///
137/// This is actually a bit of a tricky constraint in general. We
138/// want to say that each variable (e.g., `'0`) can only take on
139/// values that were supplied as arguments to the opaque type
140/// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
141/// scope. We don't have a constraint quite of this kind in the current
142/// region checker.
143///
144/// # The Solution
145///
146/// We generally prefer to make `<=` constraints, since they
147/// integrate best into the region solver. To do that, we find the
148/// "minimum" of all the arguments that appear in the args: that
149/// is, some region which is less than all the others. In the case
150/// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
151/// all). Then we apply that as a least bound to the variables
152/// (e.g., `'a <= '0`).
153///
154/// In some cases, there is no minimum. Consider this example:
155///
156/// ```text
157/// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
158/// ```
159///
160/// Here we would report a more complex "in constraint", like `'r
161/// in ['a, 'b, 'static]` (where `'r` is some region appearing in
162/// the hidden type).
163///
164/// # Constrain regions, not the hidden concrete type
165///
166/// Note that generating constraints on each region `Rc` is *not*
167/// the same as generating an outlives constraint on `Tc` itself.
168/// For example, if we had a function like this:
169///
170/// ```
171/// # #![feature(type_alias_impl_trait)]
172/// # fn main() {}
173/// # trait Foo<'a> {}
174/// # impl<'a, T> Foo<'a> for (&'a u32, T) {}
175/// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
176/// (x, y)
177/// }
178///
179/// // Equivalent to:
180/// # mod dummy { use super::*;
181/// type FooReturn<'a, T> = impl Foo<'a>;
182/// #[define_opaque(FooReturn)]
183/// fn foo<'a, T>(x: &'a u32, y: T) -> FooReturn<'a, T> {
184/// (x, y)
185/// }
186/// # }
187/// ```
188///
189/// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
190/// is an inference variable). If we generated a constraint that
191/// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
192/// but this is not necessary, because the opaque type we
193/// create will be allowed to reference `T`. So we only generate a
194/// constraint that `'0: 'a`.
195fn register_member_constraints<'tcx>(
196 typeck: &mut TypeChecker<'_, 'tcx>,
197 member_constraints: &mut MemberConstraintSet<'tcx, ty::RegionVid>,
198 opaque_type_key: OpaqueTypeKey<'tcx>,
199 OpaqueHiddenType { span, ty: hidden_ty }: OpaqueHiddenType<'tcx>,
200) {
201 let tcx = typeck.tcx();
202 let hidden_ty = typeck.infcx.resolve_vars_if_possible(hidden_ty);
203 debug!(?hidden_ty);
204
205 let variances = tcx.variances_of(opaque_type_key.def_id);
206 debug!(?variances);
207
208 // For a case like `impl Foo<'a, 'b>`, we would generate a constraint
209 // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
210 // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`).
211 //
212 // `conflict1` and `conflict2` are the two region bounds that we
213 // detected which were unrelated. They are used for diagnostics.
214
215 // Create the set of choice regions: each region in the hidden
216 // type can be equal to any of the region parameters of the
217 // opaque type definition.
218 let fr_static = typeck.universal_regions.fr_static;
219 let choice_regions: Vec<_> = opaque_type_key
220 .args
221 .iter()
222 .enumerate()
223 .filter(|(i, _)| variances[*i] == ty::Invariant)
224 .filter_map(|(_, arg)| match arg.unpack() {
225 GenericArgKind::Lifetime(r) => Some(typeck.to_region_vid(r)),
226 GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
227 })
228 .chain(iter::once(fr_static))
229 .collect();
230
231 // FIXME(#42940): This should use the `FreeRegionsVisitor`, but that's
232 // not currently sound until we have existential regions.
233 hidden_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
234 tcx,
235 op: |r| {
236 member_constraints.add_member_constraint(
237 opaque_type_key,
238 hidden_ty,
239 span,
240 typeck.to_region_vid(r),
241 &choice_regions,
242 )
243 },
244 });
245}
246
247/// Visitor that requires that (almost) all regions in the type visited outlive
248/// `least_region`. We cannot use `push_outlives_components` because regions in
249/// closure signatures are not included in their outlives components. We need to
250/// ensure all regions outlive the given bound so that we don't end up with,
251/// say, `ReVar` appearing in a return type and causing ICEs when other
252/// functions end up with region constraints involving regions from other
253/// functions.
254///
255/// We also cannot use `for_each_free_region` because for closures it includes
256/// the regions parameters from the enclosing item.
257///
258/// We ignore any type parameters because impl trait values are assumed to
259/// capture all the in-scope type parameters.
260struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
261 tcx: TyCtxt<'tcx>,
262 op: OP,
263}
264
265impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
266where
267 OP: FnMut(ty::Region<'tcx>),
268{
269 fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
270 t.super_visit_with(self);
271 }
272
273 fn visit_region(&mut self, r: ty::Region<'tcx>) {
274 match *r {
275 // ignore bound regions, keep visiting
276 ty::ReBound(_, _) => {}
277 _ => (self.op)(r),
278 }
279 }
280
281 fn visit_ty(&mut self, ty: Ty<'tcx>) {
282 // We're only interested in types involving regions
283 if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
284 return;
285 }
286
287 match *ty.kind() {
288 ty::Closure(_, args) => {
289 // Skip lifetime parameters of the enclosing item(s)
290
291 for upvar in args.as_closure().upvar_tys() {
292 upvar.visit_with(self);
293 }
294 args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
295 }
296
297 ty::CoroutineClosure(_, args) => {
298 // Skip lifetime parameters of the enclosing item(s)
299
300 for upvar in args.as_coroutine_closure().upvar_tys() {
301 upvar.visit_with(self);
302 }
303
304 args.as_coroutine_closure().signature_parts_ty().visit_with(self);
305 }
306
307 ty::Coroutine(_, args) => {
308 // Skip lifetime parameters of the enclosing item(s)
309 // Also skip the witness type, because that has no free regions.
310
311 for upvar in args.as_coroutine().upvar_tys() {
312 upvar.visit_with(self);
313 }
314 args.as_coroutine().return_ty().visit_with(self);
315 args.as_coroutine().yield_ty().visit_with(self);
316 args.as_coroutine().resume_ty().visit_with(self);
317 }
318
319 ty::Alias(kind, ty::AliasTy { def_id, args, .. })
320 if let Some(variances) = self.tcx.opt_alias_variances(kind, def_id) =>
321 {
322 // Skip lifetime parameters that are not captured, since they do
323 // not need member constraints registered for them; we'll erase
324 // them (and hopefully in the future replace them with placeholders).
325 for (v, s) in std::iter::zip(variances, args.iter()) {
326 if *v != ty::Bivariant {
327 s.visit_with(self);
328 }
329 }
330 }
331
332 _ => {
333 ty.super_visit_with(self);
334 }
335 }
336 }
337}