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}
;
9 use rustc_trait_selection
::opaque_types
::InferCtxtExt
;
11 use super::RegionInferenceContext
;
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.
17 /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
18 /// This is lowered to give HIR something like
20 /// type f<'a>::_Return<'_a> = impl Sized + '_a;
21 /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
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.
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`.
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
38 /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
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`.
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(
56 infcx
: &InferCtxt
<'_
, 'tcx
>,
57 opaque_ty_decls
: VecMap
<OpaqueTypeKey
<'tcx
>, OpaqueTypeDecl
<'tcx
>>,
59 ) -> VecMap
<OpaqueTypeKey
<'tcx
>, Ty
<'tcx
>> {
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
);
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(|| {
75 .delay_span_bug(span
, "opaque type with non-universal region substs");
76 infcx
.tcx
.lifetimes
.re_static
81 subst_regions
.dedup();
83 let universal_concrete_type
=
84 infcx
.tcx
.fold_regions(concrete_type
, &mut false, |region
, _
| match *region
{
85 ty
::ReVar(vid
) => subst_regions
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
),
93 debug
!(?universal_concrete_type
, ?universal_substs
);
96 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }
;
97 let remapped_type
= infcx
.infer_opaque_definition_from_instantiation(
99 universal_concrete_type
,
103 check_opaque_type_parameter_valid(
106 OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }
,
108 .then_some((opaque_type_key
, remapped_type
))
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
121 T
: TypeFoldable
<'tcx
>,
123 tcx
.fold_regions(ty
, &mut false, |region
, _
| match *region
{
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
{
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
{
136 Some(&ty
::ReStatic
) => {}
137 Some(region
) => return region
,
149 fn check_opaque_type_parameter_valid(
151 opaque_type_key
: OpaqueTypeKey
<'_
>,
152 decl
: OpaqueTypeDecl
<'_
>,
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
159 // fn foo<P0..Pn>() -> impl Trait
164 // fn foo<P0..Pn>() -> Foo<P0...Pn>.
166 // For lifetime parameters we convert
168 // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
172 // type foo::<'p0..'pn>::Foo<'q0..'qm>
173 // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
175 // which would error here on all of the `'static` args.
176 OpaqueTyOrigin
::FnReturn
| OpaqueTyOrigin
::AsyncFn
=> return true,
178 OpaqueTyOrigin
::TyAlias
=> {}
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
) => {
188 .struct_span_err(span
, "non-defining opaque type use in defining scope")
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 \
198 GenericArgKind
::Lifetime(lt
) => {
199 matches
!(lt
, ty
::ReEarlyBound(_
) | ty
::ReFree(_
))
201 GenericArgKind
::Const(ct
) => matches
!(ct
.val
, ty
::ConstKind
::Param(_
)),
205 seen_params
.entry(arg
).or_default().push(i
);
207 // Prevent `fn foo() -> Foo<u32>` from being defining.
208 let opaque_param
= opaque_generics
.param_at(i
, tcx
);
210 .struct_span_err(span
, "non-defining opaque type use in defining scope")
212 tcx
.def_span(opaque_param
.def_id
),
214 "used non-generic {} `{}` for generic parameter",
215 opaque_param
.kind
.descr(),
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
229 .map(|i
| tcx
.def_span(opaque_generics
.param_at(i
, tcx
).def_id
))
232 .struct_span_err(span
, "non-defining opaque type use in defining scope")
233 .span_note(spans
, &format
!("{} used multiple times", descr
))