@@ -257,10 +257,46 @@ impl<'tcx> TyCtxt<'tcx> {
257
257
false
258
258
}
259
259
260
- /// Returns the deeply last field of nested structures, or the same type,
261
- /// if not a structure at all. Corresponds to the only possible unsized
262
- /// field, and its type can be used to determine unsizing strategy.
263
- pub fn struct_tail ( self , mut ty : Ty < ' tcx > ) -> Ty < ' tcx > {
260
+ /// Attempts to returns the deeply last field of nested structures, but
261
+ /// does not apply any normalization in its search. Returns the same type
262
+ /// if input `ty` is not a structure at all.
263
+ pub fn struct_tail_without_normalization ( self , ty : Ty < ' tcx > ) -> Ty < ' tcx >
264
+ {
265
+ let tcx = self ;
266
+ tcx. struct_tail_with_normalize ( ty, |ty| ty)
267
+ }
268
+
269
+ /// Returns the deeply last field of nested structures, or the same type if
270
+ /// not a structure at all. Corresponds to the only possible unsized field,
271
+ /// and its type can be used to determine unsizing strategy.
272
+ ///
273
+ /// Should only be called if `ty` has no inference variables and does not
274
+ /// need its lifetimes preserved (e.g. as part of codegen); otherwise
275
+ /// normalization attempt may cause compiler bugs.
276
+ pub fn struct_tail_erasing_lifetimes ( self ,
277
+ ty : Ty < ' tcx > ,
278
+ param_env : ty:: ParamEnv < ' tcx > )
279
+ -> Ty < ' tcx >
280
+ {
281
+ let tcx = self ;
282
+ tcx. struct_tail_with_normalize ( ty, |ty| tcx. normalize_erasing_regions ( param_env, ty) )
283
+ }
284
+
285
+ /// Returns the deeply last field of nested structures, or the same type if
286
+ /// not a structure at all. Corresponds to the only possible unsized field,
287
+ /// and its type can be used to determine unsizing strategy.
288
+ ///
289
+ /// This is parameterized over the normalization strategy (i.e. how to
290
+ /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
291
+ /// function to indicate no normalization should take place.
292
+ ///
293
+ /// See also `struct_tail_erasing_lifetimes`, which is suitable for use
294
+ /// during codegen.
295
+ pub fn struct_tail_with_normalize ( self ,
296
+ mut ty : Ty < ' tcx > ,
297
+ normalize : impl Fn ( Ty < ' tcx > ) -> Ty < ' tcx > )
298
+ -> Ty < ' tcx >
299
+ {
264
300
loop {
265
301
match ty. sty {
266
302
ty:: Adt ( def, substs) => {
@@ -281,6 +317,15 @@ impl<'tcx> TyCtxt<'tcx> {
281
317
}
282
318
}
283
319
320
+ ty:: Projection ( _) | ty:: Opaque ( ..) => {
321
+ let normalized = normalize ( ty) ;
322
+ if ty == normalized {
323
+ return ty;
324
+ } else {
325
+ ty = normalized;
326
+ }
327
+ }
328
+
284
329
_ => {
285
330
break ;
286
331
}
@@ -294,10 +339,35 @@ impl<'tcx> TyCtxt<'tcx> {
294
339
/// structure definitions.
295
340
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
296
341
/// whereas struct_tail produces `T`, and `Trait`, respectively.
297
- pub fn struct_lockstep_tails ( self ,
298
- source : Ty < ' tcx > ,
299
- target : Ty < ' tcx > )
300
- -> ( Ty < ' tcx > , Ty < ' tcx > ) {
342
+ ///
343
+ /// Should only be called if the types have no inference variables and do
344
+ /// not need their lifetimes preserved (e.g. as part of codegen); otherwise
345
+ /// normalization attempt may cause compiler bugs.
346
+ pub fn struct_lockstep_tails_erasing_lifetimes ( self ,
347
+ source : Ty < ' tcx > ,
348
+ target : Ty < ' tcx > ,
349
+ param_env : ty:: ParamEnv < ' tcx > )
350
+ -> ( Ty < ' tcx > , Ty < ' tcx > )
351
+ {
352
+ let tcx = self ;
353
+ tcx. struct_lockstep_tails_with_normalize (
354
+ source, target, |ty| tcx. normalize_erasing_regions ( param_env, ty) )
355
+ }
356
+
357
+ /// Same as applying struct_tail on `source` and `target`, but only
358
+ /// keeps going as long as the two types are instances of the same
359
+ /// structure definitions.
360
+ /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
361
+ /// whereas struct_tail produces `T`, and `Trait`, respectively.
362
+ ///
363
+ /// See also `struct_lockstep_tails_erasing_lifetimes`, which is suitable for use
364
+ /// during codegen.
365
+ pub fn struct_lockstep_tails_with_normalize ( self ,
366
+ source : Ty < ' tcx > ,
367
+ target : Ty < ' tcx > ,
368
+ normalize : impl Fn ( Ty < ' tcx > ) -> Ty < ' tcx > )
369
+ -> ( Ty < ' tcx > , Ty < ' tcx > )
370
+ {
301
371
let ( mut a, mut b) = ( source, target) ;
302
372
loop {
303
373
match ( & a. sty , & b. sty ) {
@@ -319,6 +389,22 @@ impl<'tcx> TyCtxt<'tcx> {
319
389
break ;
320
390
}
321
391
} ,
392
+ ( ty:: Projection ( _) , _) | ( ty:: Opaque ( ..) , _) |
393
+ ( _, ty:: Projection ( _) ) | ( _, ty:: Opaque ( ..) ) => {
394
+ // If either side is a projection, attempt to
395
+ // progress via normalization. (Should be safe to
396
+ // apply to both sides as normalization is
397
+ // idempotent.)
398
+ let a_norm = normalize ( a) ;
399
+ let b_norm = normalize ( b) ;
400
+ if a == a_norm && b == b_norm {
401
+ break ;
402
+ } else {
403
+ a = a_norm;
404
+ b = b_norm;
405
+ }
406
+ }
407
+
322
408
_ => break ,
323
409
}
324
410
}
0 commit comments