@@ -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