]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Rollup merge of #93613 - crlf0710:rename_to_async_iter, r=yaahc
[rust.git] / compiler / rustc_borrowck / src / region_infer / opaque_types.rs
1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_data_structures::vec_map::VecMap;
3 use rustc_hir::OpaqueTyOrigin;
4 use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
5 use rustc_infer::infer::InferCtxt;
6 use rustc_middle::ty::subst::GenericArgKind;
7 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
8 use rustc_span::Span;
9 use rustc_trait_selection::opaque_types::InferCtxtExt;
10
11 use super::RegionInferenceContext;
12
13 impl<'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`.
53     #[instrument(level = "debug", skip(self, infcx))]
54     pub(crate) fn infer_opaque_types(
55         &self,
56         infcx: &InferCtxt<'_, 'tcx>,
57         opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
58         span: Span,
59     ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
60         opaque_ty_decls
61             .into_iter()
62             .filter_map(|(opaque_type_key, decl)| {
63                 let substs = opaque_type_key.substs;
64                 let concrete_type = decl.concrete_ty;
65                 debug!(?concrete_type, ?substs);
66
67                 let mut subst_regions = vec![self.universal_regions.fr_static];
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                 });
79
80                 subst_regions.sort();
81                 subst_regions.dedup();
82
83                 let universal_concrete_type =
84                     infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
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),
90                         _ => region,
91                     });
92
93                 debug!(?universal_concrete_type, ?universal_substs);
94
95                 let opaque_type_key =
96                     OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
97                 let remapped_type = infcx.infer_opaque_definition_from_instantiation(
98                     opaque_type_key,
99                     universal_concrete_type,
100                     span,
101                 );
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))
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.
119     pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
120     where
121         T: TypeFoldable<'tcx>,
122     {
123         tcx.fold_regions(ty, &mut false, |region, _| match *region {
124             ty::ReVar(vid) => {
125                 // Find something that we can name
126                 let upper_bound = self.approx_universal_upper_bound(vid);
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(region) if region.is_static() => {}
137                                 Some(region) => return region,
138                             }
139                         }
140                         region
141                     }
142                 }
143             }
144             _ => region,
145         })
146     }
147 }
148
149 fn 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.
176         OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
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(lt) if lt.is_static() => {
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 }