@@ -253,6 +253,45 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
253253 return err_info;
254254 }
255255
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>`.
256295 let fields = & def_a. struct_variant ( ) . fields ;
257296 let diff_fields = fields. iter ( )
258297 . enumerate ( )
@@ -264,8 +303,16 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
264303 return None ;
265304 }
266305
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) {
269316 if ok. obligations . is_empty ( ) {
270317 return None ;
271318 }
0 commit comments