1
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
1
+ use rustc_data_structures:: fx:: FxIndexMap ;
2
2
use rustc_errors:: ErrorGuaranteed ;
3
3
use rustc_hir:: def:: DefKind ;
4
4
use rustc_hir:: def_id:: LocalDefId ;
5
5
use rustc_hir:: OpaqueTyOrigin ;
6
- use rustc_infer:: infer:: InferCtxt ;
7
6
use rustc_infer:: infer:: TyCtxtInferExt as _;
7
+ use rustc_infer:: infer:: { InferCtxt , NllRegionVariableOrigin } ;
8
8
use rustc_infer:: traits:: { Obligation , ObligationCause } ;
9
9
use rustc_macros:: extension;
10
10
use rustc_middle:: traits:: DefiningAnchor ;
@@ -95,39 +95,43 @@ impl<'tcx> RegionInferenceContext<'tcx> {
95
95
/// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
96
96
/// This is lowered to give HIR something like
97
97
///
98
- /// type f<'a>::_Return<'_a > = impl Sized + '_a ;
99
- /// fn f<'a>(x: &'a i32) -> f<'static >::_Return<'a> { x }
98
+ /// type f<'a>::_Return<'_x > = impl Sized + '_x ;
99
+ /// fn f<'a>(x: &'a i32) -> f<'a >::_Return<'a> { x }
100
100
///
101
101
/// When checking the return type record the type from the return and the
102
102
/// type used in the return value. In this case they might be `_Return<'1>`
103
103
/// and `&'2 i32` respectively.
104
104
///
105
105
/// Once we to this method, we have completed region inference and want to
106
106
/// call `infer_opaque_definition_from_instantiation` to get the inferred
107
- /// type of `_Return<'_a >`. `infer_opaque_definition_from_instantiation`
107
+ /// type of `_Return<'_x >`. `infer_opaque_definition_from_instantiation`
108
108
/// compares lifetimes directly, so we need to map the inference variables
109
109
/// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`.
110
110
///
111
- /// First we map all the lifetimes in the concrete type to an equal
112
- /// universal region that occurs in the concrete type's args, in this case
113
- /// this would result in `&'1 i32`. We only consider regions in the args
111
+ /// First we map the regions in the the generic parameters `_Return<'1>` to
112
+ /// their `external_name` giving `_Return<'a>`. This step is a bit involved.
113
+ /// See the [rustc-dev-guide chapter] for more info.
114
+ ///
115
+ /// Then we map all the lifetimes in the concrete type to an equal
116
+ /// universal region that occurs in the opaque type's args, in this case
117
+ /// this would result in `&'a i32`. We only consider regions in the args
114
118
/// in case there is an equal region that does not. For example, this should
115
119
/// be allowed:
116
120
/// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
117
121
///
118
- /// Then we map the regions in both the type and the generic parameters to their
119
- /// `external_name` giving `concrete_type = &'a i32`,
120
- /// `args = ['static, 'a]`. This will then allow
121
- /// `infer_opaque_definition_from_instantiation` to determine that
122
- /// `_Return<'_a> = &'_a i32`.
122
+ /// This will then allow `infer_opaque_definition_from_instantiation` to
123
+ /// determine that `_Return<'_x> = &'_x i32`.
123
124
///
124
125
/// There's a slight complication around closures. Given
125
126
/// `fn f<'a: 'a>() { || {} }` the closure's type is something like
126
127
/// `f::<'a>::{{closure}}`. The region parameter from f is essentially
127
128
/// ignored by type checking so ends up being inferred to an empty region.
128
129
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
129
- /// which has no `external_name` in which case we use `'empty ` as the
130
+ /// which has no `external_name` in which case we use `'{erased} ` as the
130
131
/// region to pass to `infer_opaque_definition_from_instantiation`.
132
+ ///
133
+ /// [rustc-dev-guide chapter]:
134
+ /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
131
135
#[ instrument( level = "debug" , skip( self , infcx) , ret) ]
132
136
pub ( crate ) fn infer_opaque_types (
133
137
& self ,
@@ -138,85 +142,59 @@ impl<'tcx> RegionInferenceContext<'tcx> {
138
142
139
143
let mut result: FxIndexMap < LocalDefId , OpaqueHiddenType < ' tcx > > = FxIndexMap :: default ( ) ;
140
144
141
- let member_constraints: FxIndexMap < _ , _ > = self
142
- . member_constraints
143
- . all_indices ( )
144
- . map ( |ci| ( self . member_constraints [ ci] . key , ci) )
145
- . collect ( ) ;
146
- debug ! ( ?member_constraints) ;
147
-
148
145
for ( opaque_type_key, concrete_type) in opaque_ty_decls {
149
- let args = opaque_type_key. args ;
150
- debug ! ( ?concrete_type, ?args) ;
146
+ debug ! ( ?opaque_type_key, ?concrete_type) ;
151
147
152
- let mut arg_regions = vec ! [ self . universal_regions. fr_static] ;
148
+ let mut arg_regions: Vec < ( ty:: RegionVid , ty:: Region < ' _ > ) > =
149
+ vec ! [ ( self . universal_regions. fr_static, infcx. tcx. lifetimes. re_static) ] ;
153
150
154
- let to_universal_region = |vid, arg_regions : & mut Vec < _ > | match self . universal_name ( vid)
155
- {
156
- Some ( region) => {
157
- let vid = self . universal_regions . to_region_vid ( region) ;
158
- arg_regions. push ( vid) ;
159
- region
160
- }
161
- None => {
162
- arg_regions. push ( vid) ;
163
- ty:: Region :: new_error_with_message (
164
- infcx. tcx ,
165
- concrete_type. span ,
166
- "opaque type with non-universal region args" ,
167
- )
168
- }
169
- } ;
151
+ let opaque_type_key =
152
+ opaque_type_key. fold_captured_lifetime_args ( infcx. tcx , |region| {
153
+ // Use the SCC representative instead of directly using `region`.
154
+ // See [rustc-dev-guide chapter] § "Strict lifetime equality".
155
+ let scc = self . constraint_sccs . scc ( region. as_var ( ) ) ;
156
+ let vid = self . scc_representatives [ scc] ;
157
+ let named = match self . definitions [ vid] . origin {
158
+ // Iterate over all universal regions in a consistent order and find the
159
+ // *first* equal region. This makes sure that equal lifetimes will have
160
+ // the same name and simplifies subsequent handling.
161
+ // See [rustc-dev-guide chapter] § "Semantic lifetime equality".
162
+ NllRegionVariableOrigin :: FreeRegion => self
163
+ . universal_regions
164
+ . universal_regions ( )
165
+ . filter ( |& ur| self . universal_region_relations . equal ( vid, ur) )
166
+ // FIXME(aliemjay): universal regions with no `external_name`
167
+ // are extenal closure regions, which should be rejected eventually.
168
+ . find_map ( |ur| self . definitions [ ur] . external_name ) ,
169
+ NllRegionVariableOrigin :: Placeholder ( placeholder) => {
170
+ Some ( ty:: Region :: new_placeholder ( infcx. tcx , placeholder) )
171
+ }
172
+ NllRegionVariableOrigin :: Existential { .. } => None ,
173
+ }
174
+ . unwrap_or_else ( || {
175
+ ty:: Region :: new_error_with_message (
176
+ infcx. tcx ,
177
+ concrete_type. span ,
178
+ "opaque type with non-universal region args" ,
179
+ )
180
+ } ) ;
170
181
171
- // Start by inserting universal regions from the member_constraint choice regions.
172
- // This will ensure they get precedence when folding the regions in the concrete type.
173
- if let Some ( & ci) = member_constraints. get ( & opaque_type_key) {
174
- for & vid in self . member_constraints . choice_regions ( ci) {
175
- to_universal_region ( vid, & mut arg_regions) ;
176
- }
177
- }
178
- debug ! ( ?arg_regions) ;
179
-
180
- // Next, insert universal regions from args, so we can translate regions that appear
181
- // in them but are not subject to member constraints, for instance closure args.
182
- let universal_key = opaque_type_key. fold_captured_lifetime_args ( infcx. tcx , |region| {
183
- if let ty:: RePlaceholder ( ..) = region. kind ( ) {
184
- // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args.
185
- return region;
186
- }
187
- let vid = self . to_region_vid ( region) ;
188
- to_universal_region ( vid, & mut arg_regions)
189
- } ) ;
190
- let universal_args = universal_key. args ;
191
- debug ! ( ?universal_args) ;
192
- debug ! ( ?arg_regions) ;
193
-
194
- // Deduplicate the set of regions while keeping the chosen order.
195
- let arg_regions = arg_regions. into_iter ( ) . collect :: < FxIndexSet < _ > > ( ) ;
196
- debug ! ( ?arg_regions) ;
197
-
198
- let universal_concrete_type =
199
- infcx. tcx . fold_regions ( concrete_type, |region, _| match * region {
200
- ty:: ReVar ( vid) => arg_regions
201
- . iter ( )
202
- . find ( |ur_vid| self . eval_equal ( vid, * * ur_vid) )
203
- . and_then ( |ur_vid| self . definitions [ * ur_vid] . external_name )
204
- . unwrap_or ( infcx. tcx . lifetimes . re_erased ) ,
205
- ty:: RePlaceholder ( _) => ty:: Region :: new_error_with_message (
206
- infcx. tcx ,
207
- concrete_type. span ,
208
- "hidden type contains placeholders, we don't support higher kinded opaques yet" ,
209
- ) ,
210
- _ => region,
182
+ arg_regions. push ( ( vid, named) ) ;
183
+ named
211
184
} ) ;
212
- debug ! ( ?universal_concrete_type) ;
185
+ debug ! ( ?opaque_type_key, ?arg_regions) ;
186
+
187
+ let concrete_type = infcx. tcx . fold_regions ( concrete_type, |region, _| {
188
+ arg_regions
189
+ . iter ( )
190
+ . find ( |& & ( arg_vid, _) | self . eval_equal ( region. as_var ( ) , arg_vid) )
191
+ . map ( |& ( _, arg_named) | arg_named)
192
+ . unwrap_or ( infcx. tcx . lifetimes . re_erased )
193
+ } ) ;
194
+ debug ! ( ?concrete_type) ;
213
195
214
- let opaque_type_key =
215
- OpaqueTypeKey { def_id : opaque_type_key. def_id , args : universal_args } ;
216
- let ty = infcx. infer_opaque_definition_from_instantiation (
217
- opaque_type_key,
218
- universal_concrete_type,
219
- ) ;
196
+ let ty =
197
+ infcx. infer_opaque_definition_from_instantiation ( opaque_type_key, concrete_type) ;
220
198
// Sometimes two opaque types are the same only after we remap the generic parameters
221
199
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
222
200
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
0 commit comments