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