]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/opaque_types.rs
Rollup merge of #91770 - TaKO8Ki:suggest-adding-cfg-test, r=joshtriplett
[rust.git] / compiler / rustc_trait_selection / src / opaque_types.rs
1 use crate::traits;
2 use rustc_data_structures::fx::FxHashMap;
3 use rustc_hir::def_id::DefId;
4 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
5 use rustc_infer::infer::InferCtxt;
6 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
7 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
8 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
9 use rustc_span::Span;
10
11 pub trait InferCtxtExt<'tcx> {
12     fn infer_opaque_definition_from_instantiation(
13         &self,
14         opaque_type_key: OpaqueTypeKey<'tcx>,
15         instantiated_ty: Ty<'tcx>,
16         span: Span,
17     ) -> Ty<'tcx>;
18 }
19
20 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
21     /// Given the fully resolved, instantiated type for an opaque
22     /// type, i.e., the value of an inference variable like C1 or C2
23     /// (*), computes the "definition type" for an opaque type
24     /// definition -- that is, the inferred value of `Foo1<'x>` or
25     /// `Foo2<'x>` that we would conceptually use in its definition:
26     ///
27     ///     type Foo1<'x> = impl Bar<'x> = AAA; <-- this type AAA
28     ///     type Foo2<'x> = impl Bar<'x> = BBB; <-- or this type BBB
29     ///     fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
30     ///
31     /// Note that these values are defined in terms of a distinct set of
32     /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
33     /// purpose of this function is to do that translation.
34     ///
35     /// (*) C1 and C2 were introduced in the comments on
36     /// `constrain_opaque_type`. Read that comment for more context.
37     ///
38     /// # Parameters
39     ///
40     /// - `def_id`, the `impl Trait` type
41     /// - `substs`, the substs  used to instantiate this opaque type
42     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
43     ///   `opaque_defn.concrete_ty`
44     #[instrument(level = "debug", skip(self))]
45     fn infer_opaque_definition_from_instantiation(
46         &self,
47         opaque_type_key: OpaqueTypeKey<'tcx>,
48         instantiated_ty: Ty<'tcx>,
49         span: Span,
50     ) -> Ty<'tcx> {
51         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
52
53         // Use substs to build up a reverse map from regions to their
54         // identity mappings. This is necessary because of `impl
55         // Trait` lifetimes are computed by replacing existing
56         // lifetimes with 'static and remapping only those used in the
57         // `impl Trait` return type, resulting in the parameters
58         // shifting.
59         let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
60         debug!(?id_substs);
61         let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
62             substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
63         debug!("map = {:#?}", map);
64
65         // Convert the type from the function into a type valid outside
66         // the function, by replacing invalid regions with 'static,
67         // after producing an error for each of them.
68         let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
69             self.tcx,
70             self.is_tainted_by_errors(),
71             def_id,
72             map,
73             instantiated_ty,
74             span,
75         ));
76         debug!(?definition_ty);
77
78         definition_ty
79     }
80 }
81
82 struct ReverseMapper<'tcx> {
83     tcx: TyCtxt<'tcx>,
84
85     /// If errors have already been reported in this fn, we suppress
86     /// our own errors because they are sometimes derivative.
87     tainted_by_errors: bool,
88
89     opaque_type_def_id: DefId,
90     map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
91     map_missing_regions_to_empty: bool,
92
93     /// initially `Some`, set to `None` once error has been reported
94     hidden_ty: Option<Ty<'tcx>>,
95
96     /// Span of function being checked.
97     span: Span,
98 }
99
100 impl<'tcx> ReverseMapper<'tcx> {
101     fn new(
102         tcx: TyCtxt<'tcx>,
103         tainted_by_errors: bool,
104         opaque_type_def_id: DefId,
105         map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
106         hidden_ty: Ty<'tcx>,
107         span: Span,
108     ) -> Self {
109         Self {
110             tcx,
111             tainted_by_errors,
112             opaque_type_def_id,
113             map,
114             map_missing_regions_to_empty: false,
115             hidden_ty: Some(hidden_ty),
116             span,
117         }
118     }
119
120     fn fold_kind_mapping_missing_regions_to_empty(
121         &mut self,
122         kind: GenericArg<'tcx>,
123     ) -> GenericArg<'tcx> {
124         assert!(!self.map_missing_regions_to_empty);
125         self.map_missing_regions_to_empty = true;
126         let kind = kind.fold_with(self);
127         self.map_missing_regions_to_empty = false;
128         kind
129     }
130
131     fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
132         assert!(!self.map_missing_regions_to_empty);
133         kind.fold_with(self)
134     }
135 }
136
137 impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
138     fn tcx(&self) -> TyCtxt<'tcx> {
139         self.tcx
140     }
141
142     #[instrument(skip(self), level = "debug")]
143     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
144         match r {
145             // Ignore bound regions and `'static` regions that appear in the
146             // type, we only need to remap regions that reference lifetimes
147             // from the function declaraion.
148             // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
149             ty::ReLateBound(..) | ty::ReStatic => return r,
150
151             // If regions have been erased (by writeback), don't try to unerase
152             // them.
153             ty::ReErased => return r,
154
155             // The regions that we expect from borrow checking.
156             ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
157
158             ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
159                 // All of the regions in the type should either have been
160                 // erased by writeback, or mapped back to named regions by
161                 // borrow checking.
162                 bug!("unexpected region kind in opaque type: {:?}", r);
163             }
164         }
165
166         let generics = self.tcx().generics_of(self.opaque_type_def_id);
167         match self.map.get(&r.into()).map(|k| k.unpack()) {
168             Some(GenericArgKind::Lifetime(r1)) => r1,
169             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
170             None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
171                 self.tcx.lifetimes.re_root_empty
172             }
173             None if generics.parent.is_some() => {
174                 if let Some(hidden_ty) = self.hidden_ty.take() {
175                     unexpected_hidden_region_diagnostic(
176                         self.tcx,
177                         self.tcx.def_span(self.opaque_type_def_id),
178                         hidden_ty,
179                         r,
180                     )
181                     .emit();
182                 }
183                 self.tcx.lifetimes.re_root_empty
184             }
185             None => {
186                 self.tcx
187                     .sess
188                     .struct_span_err(self.span, "non-defining opaque type use in defining scope")
189                     .span_label(
190                         self.span,
191                         format!(
192                             "lifetime `{}` is part of concrete type but not used in \
193                                  parameter list of the `impl Trait` type alias",
194                             r
195                         ),
196                     )
197                     .emit();
198
199                 self.tcx().lifetimes.re_static
200             }
201         }
202     }
203
204     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
205         match *ty.kind() {
206             ty::Closure(def_id, substs) => {
207                 // I am a horrible monster and I pray for death. When
208                 // we encounter a closure here, it is always a closure
209                 // from within the function that we are currently
210                 // type-checking -- one that is now being encapsulated
211                 // in an opaque type. Ideally, we would
212                 // go through the types/lifetimes that it references
213                 // and treat them just like we would any other type,
214                 // which means we would error out if we find any
215                 // reference to a type/region that is not in the
216                 // "reverse map".
217                 //
218                 // **However,** in the case of closures, there is a
219                 // somewhat subtle (read: hacky) consideration. The
220                 // problem is that our closure types currently include
221                 // all the lifetime parameters declared on the
222                 // enclosing function, even if they are unused by the
223                 // closure itself. We can't readily filter them out,
224                 // so here we replace those values with `'empty`. This
225                 // can't really make a difference to the rest of the
226                 // compiler; those regions are ignored for the
227                 // outlives relation, and hence don't affect trait
228                 // selection or auto traits, and they are erased
229                 // during codegen.
230
231                 let generics = self.tcx.generics_of(def_id);
232                 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
233                     if index < generics.parent_count {
234                         // Accommodate missing regions in the parent kinds...
235                         self.fold_kind_mapping_missing_regions_to_empty(kind)
236                     } else {
237                         // ...but not elsewhere.
238                         self.fold_kind_normally(kind)
239                     }
240                 }));
241
242                 self.tcx.mk_closure(def_id, substs)
243             }
244
245             ty::Generator(def_id, substs, movability) => {
246                 let generics = self.tcx.generics_of(def_id);
247                 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
248                     if index < generics.parent_count {
249                         // Accommodate missing regions in the parent kinds...
250                         self.fold_kind_mapping_missing_regions_to_empty(kind)
251                     } else {
252                         // ...but not elsewhere.
253                         self.fold_kind_normally(kind)
254                     }
255                 }));
256
257                 self.tcx.mk_generator(def_id, substs, movability)
258             }
259
260             ty::Param(param) => {
261                 // Look it up in the substitution list.
262                 match self.map.get(&ty.into()).map(|k| k.unpack()) {
263                     // Found it in the substitution list; replace with the parameter from the
264                     // opaque type.
265                     Some(GenericArgKind::Type(t1)) => t1,
266                     Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
267                     None => {
268                         debug!(?param, ?self.map);
269                         self.tcx
270                             .sess
271                             .struct_span_err(
272                                 self.span,
273                                 &format!(
274                                     "type parameter `{}` is part of concrete type but not \
275                                           used in parameter list for the `impl Trait` type alias",
276                                     ty
277                                 ),
278                             )
279                             .emit();
280
281                         self.tcx().ty_error()
282                     }
283                 }
284             }
285
286             _ => ty.super_fold_with(self),
287         }
288     }
289
290     fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
291         trace!("checking const {:?}", ct);
292         // Find a const parameter
293         match ct.val {
294             ty::ConstKind::Param(..) => {
295                 // Look it up in the substitution list.
296                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
297                     // Found it in the substitution list, replace with the parameter from the
298                     // opaque type.
299                     Some(GenericArgKind::Const(c1)) => c1,
300                     Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
301                     None => {
302                         self.tcx
303                             .sess
304                             .struct_span_err(
305                                 self.span,
306                                 &format!(
307                                     "const parameter `{}` is part of concrete type but not \
308                                           used in parameter list for the `impl Trait` type alias",
309                                     ct
310                                 ),
311                             )
312                             .emit();
313
314                         self.tcx().const_error(ct.ty)
315                     }
316                 }
317             }
318
319             _ => ct,
320         }
321     }
322 }
323
324 /// Given a set of predicates that apply to an object type, returns
325 /// the region bounds that the (erased) `Self` type must
326 /// outlive. Precisely *because* the `Self` type is erased, the
327 /// parameter `erased_self_ty` must be supplied to indicate what type
328 /// has been used to represent `Self` in the predicates
329 /// themselves. This should really be a unique type; `FreshTy(0)` is a
330 /// popular choice.
331 ///
332 /// N.B., in some cases, particularly around higher-ranked bounds,
333 /// this function returns a kind of conservative approximation.
334 /// That is, all regions returned by this function are definitely
335 /// required, but there may be other region bounds that are not
336 /// returned, as well as requirements like `for<'a> T: 'a`.
337 ///
338 /// Requires that trait definitions have been processed so that we can
339 /// elaborate predicates and walk supertraits.
340 #[instrument(skip(tcx, predicates), level = "debug")]
341 crate fn required_region_bounds<'tcx>(
342     tcx: TyCtxt<'tcx>,
343     erased_self_ty: Ty<'tcx>,
344     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
345 ) -> Vec<ty::Region<'tcx>> {
346     assert!(!erased_self_ty.has_escaping_bound_vars());
347
348     traits::elaborate_predicates(tcx, predicates)
349         .filter_map(|obligation| {
350             debug!(?obligation);
351             match obligation.predicate.kind().skip_binder() {
352                 ty::PredicateKind::Projection(..)
353                 | ty::PredicateKind::Trait(..)
354                 | ty::PredicateKind::Subtype(..)
355                 | ty::PredicateKind::Coerce(..)
356                 | ty::PredicateKind::WellFormed(..)
357                 | ty::PredicateKind::ObjectSafe(..)
358                 | ty::PredicateKind::ClosureKind(..)
359                 | ty::PredicateKind::RegionOutlives(..)
360                 | ty::PredicateKind::ConstEvaluatable(..)
361                 | ty::PredicateKind::ConstEquate(..)
362                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
363                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
364                     // Search for a bound of the form `erased_self_ty
365                     // : 'a`, but be wary of something like `for<'a>
366                     // erased_self_ty : 'a` (we interpret a
367                     // higher-ranked bound like that as 'static,
368                     // though at present the code in `fulfill.rs`
369                     // considers such bounds to be unsatisfiable, so
370                     // it's kind of a moot point since you could never
371                     // construct such an object, but this seems
372                     // correct even if that code changes).
373                     if t == &erased_self_ty && !r.has_escaping_bound_vars() {
374                         Some(*r)
375                     } else {
376                         None
377                     }
378                 }
379             }
380         })
381         .collect()
382 }