@@ -254,6 +254,45 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
254
254
return err_info;
255
255
}
256
256
257
+ // Here we are considering a case of converting
258
+ // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
259
+ // which acts like a pointer to `U`, but carries along some extra data of type `T`:
260
+ //
261
+ // struct Foo<T, U> {
262
+ // extra: T,
263
+ // ptr: *mut U,
264
+ // }
265
+ //
266
+ // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
267
+ // to `Foo<T, [i32]>`. That impl would look like:
268
+ //
269
+ // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
270
+ //
271
+ // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
272
+ // when this coercion occurs, we would be changing the
273
+ // field `ptr` from a thin pointer of type `*mut [i32;
274
+ // 3]` to a fat pointer of type `*mut [i32]` (with
275
+ // extra data `3`). **The purpose of this check is to
276
+ // make sure that we know how to do this conversion.**
277
+ //
278
+ // To check if this impl is legal, we would walk down
279
+ // the fields of `Foo` and consider their types with
280
+ // both substitutes. We are looking to find that
281
+ // exactly one (non-phantom) field has changed its
282
+ // type, which we will expect to be the pointer that
283
+ // is becoming fat (we could probably generalize this
284
+ // to mutiple thin pointers of the same type becoming
285
+ // fat, but we don't). In this case:
286
+ //
287
+ // - `extra` has type `T` before and type `T` after
288
+ // - `ptr` has type `*mut U` before and type `*mut V` after
289
+ //
290
+ // Since just one field changed, we would then check
291
+ // that `*mut U: CoerceUnsized<*mut V>` is implemented
292
+ // (in other words, that we know how to do this
293
+ // conversion). This will work out because `U:
294
+ // Unsize<V>`, and we have a builtin rule that `*mut
295
+ // U` can be coerced to `*mut V` if `U: Unsize<V>`.
257
296
let fields = & def_a. struct_variant ( ) . fields ;
258
297
let diff_fields = fields. iter ( )
259
298
. enumerate ( )
@@ -265,8 +304,16 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
265
304
return None ;
266
305
}
267
306
268
- // Ignore fields that aren't significantly changed
269
- if let Ok ( ok) = infcx. sub_types ( false , & cause, b, a) {
307
+ // Ignore fields that aren't changed; it may
308
+ // be that we could get away with subtyping or
309
+ // something more accepting, but we use
310
+ // equality because we want to be able to
311
+ // perform this check without computing
312
+ // variance where possible. (This is because
313
+ // we may have to evaluate constraint
314
+ // expressions in the course of execution.)
315
+ // See e.g. #41936.
316
+ if let Ok ( ok) = infcx. eq_types ( false , & cause, b, a) {
270
317
if ok. obligations . is_empty ( ) {
271
318
return None ;
272
319
}
0 commit comments