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