@@ -4,10 +4,11 @@ use std::iter;
44
55use  super :: assembly:: { self ,  Candidate ,  CandidateSource } ; 
66use  super :: infcx_ext:: InferCtxtExt ; 
7- use  super :: { Certainty ,  EvalCtxt ,  Goal ,  QueryResult } ; 
7+ use  super :: { CanonicalResponse ,   Certainty ,  EvalCtxt ,  Goal ,  QueryResult } ; 
88use  rustc_hir:: def_id:: DefId ; 
99use  rustc_infer:: infer:: InferCtxt ; 
1010use  rustc_infer:: traits:: query:: NoSolution ; 
11+ use  rustc_infer:: traits:: util:: supertraits; 
1112use  rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt ,  TreatParams } ; 
1213use  rustc_middle:: ty:: { self ,  ToPredicate ,  Ty ,  TyCtxt } ; 
1314use  rustc_middle:: ty:: { TraitPredicate ,  TypeVisitable } ; 
@@ -238,6 +239,206 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
238239            . to_predicate ( tcx) , 
239240        ) 
240241    } 
242+ 
243+     fn  consider_builtin_unsize_candidate ( 
244+         ecx :  & mut  EvalCtxt < ' _ ,  ' tcx > , 
245+         goal :  Goal < ' tcx ,  Self > , 
246+     )  -> QueryResult < ' tcx >  { 
247+         let  tcx = ecx. tcx ( ) ; 
248+         let  a_ty = goal. predicate . self_ty ( ) ; 
249+         let  b_ty = goal. predicate . trait_ref . substs . type_at ( 1 ) ; 
250+         if  b_ty. is_ty_var ( )  { 
251+             return  ecx. make_canonical_response ( Certainty :: AMBIGUOUS ) ; 
252+         } 
253+         ecx. infcx . probe ( |_| { 
254+             match  ( a_ty. kind ( ) ,  b_ty. kind ( ) )  { 
255+                 // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` 
256+                 ( & ty:: Dynamic ( _,  _,  ty:: Dyn ) ,  & ty:: Dynamic ( _,  _,  ty:: Dyn ) )  => { 
257+                     // Dyn upcasting is handled separately, since due to upcasting, 
258+                     // when there are two supertraits that differ by substs, we 
259+                     // may return more than one query response. 
260+                     return  Err ( NoSolution ) ; 
261+                 } 
262+                 // `T` -> `dyn Trait` unsizing 
263+                 ( _,  & ty:: Dynamic ( data,  region,  ty:: Dyn ) )  => { 
264+                     // Can only unsize to an object-safe type 
265+                     if  data
266+                         . principal_def_id ( ) 
267+                         . map_or ( false ,  |def_id| !tcx. check_is_object_safe ( def_id) ) 
268+                     { 
269+                         return  Err ( NoSolution ) ; 
270+                     } 
271+ 
272+                     let  Some ( sized_def_id)  = tcx. lang_items ( ) . sized_trait ( )  else  { 
273+                         return  Err ( NoSolution ) ; 
274+                     } ; 
275+                     let  nested_goals:  Vec < _ >  = data
276+                         . iter ( ) 
277+                         // Check that the type implements all of the predicates of the def-id. 
278+                         // (i.e. the principal, all of the associated types match, and any auto traits) 
279+                         . map ( |pred| goal. with ( tcx,  pred. with_self_ty ( tcx,  a_ty) ) ) 
280+                         . chain ( [ 
281+                             // The type must be Sized to be unsized. 
282+                             goal. with ( 
283+                                 tcx, 
284+                                 ty:: Binder :: dummy ( tcx. mk_trait_ref ( sized_def_id,  [ a_ty] ) ) , 
285+                             ) , 
286+                             // The type must outlive the lifetime of the `dyn` we're unsizing into. 
287+                             goal. with ( tcx,  ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_ty,  region) ) ) , 
288+                         ] ) 
289+                         . collect ( ) ; 
290+ 
291+                     ecx. evaluate_all_and_make_canonical_response ( nested_goals) 
292+                 } 
293+                 // `[T; n]` -> `[T]` unsizing 
294+                 ( & ty:: Array ( a_elem_ty,  ..) ,  & ty:: Slice ( b_elem_ty) )  => { 
295+                     // We just require that the element type stays the same 
296+                     let  nested_goals = ecx. infcx . eq ( goal. param_env ,  a_elem_ty,  b_elem_ty) ?; 
297+                     ecx. evaluate_all_and_make_canonical_response ( nested_goals) 
298+                 } 
299+                 // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` 
300+                 ( & ty:: Adt ( a_def,  a_substs) ,  & ty:: Adt ( b_def,  b_substs) ) 
301+                     if  a_def. is_struct ( )  && a_def. did ( )  == b_def. did ( )  =>
302+                 { 
303+                     let  unsizing_params = tcx. unsizing_params_for_adt ( a_def. did ( ) ) ; 
304+                     // We must be unsizing some type parameters. This also implies 
305+                     // that the struct has a tail field. 
306+                     if  unsizing_params. is_empty ( )  { 
307+                         return  Err ( NoSolution ) ; 
308+                     } 
309+ 
310+                     let  tail_field = a_def
311+                         . non_enum_variant ( ) 
312+                         . fields 
313+                         . last ( ) 
314+                         . expect ( "expected unsized ADT to have a tail field" ) ; 
315+                     let  tail_field_ty = tcx. bound_type_of ( tail_field. did ) ; 
316+ 
317+                     let  a_tail_ty = tail_field_ty. subst ( tcx,  a_substs) ; 
318+                     let  b_tail_ty = tail_field_ty. subst ( tcx,  b_substs) ; 
319+ 
320+                     // Substitute just the unsizing params from B into A. The type after 
321+                     // this substitution must be equal to B. This is so we don't unsize 
322+                     // unrelated type parameters. 
323+                     let  new_a_substs = tcx. mk_substs ( a_substs. iter ( ) . enumerate ( ) . map ( |( i,  a) | { 
324+                         if  unsizing_params. contains ( i as  u32 )  {  b_substs[ i]  }  else  {  a } 
325+                     } ) ) ; 
326+                     let  unsized_a_ty = tcx. mk_adt ( a_def,  new_a_substs) ; 
327+ 
328+                     // Finally, we require that `TailA: Unsize<TailB>` for the tail field 
329+                     // types. 
330+                     let  mut  nested_goals = ecx. infcx . eq ( goal. param_env ,  unsized_a_ty,  b_ty) ?; 
331+                     nested_goals. push ( goal. with ( 
332+                         tcx, 
333+                         ty:: Binder :: dummy ( 
334+                             tcx. mk_trait_ref ( goal. predicate . def_id ( ) ,  [ a_tail_ty,  b_tail_ty] ) , 
335+                         ) , 
336+                     ) ) ; 
337+ 
338+                     ecx. evaluate_all_and_make_canonical_response ( nested_goals) 
339+                 } 
340+                 // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` 
341+                 ( & ty:: Tuple ( a_tys) ,  & ty:: Tuple ( b_tys) ) 
342+                     if  a_tys. len ( )  == b_tys. len ( )  && !a_tys. is_empty ( )  =>
343+                 { 
344+                     let  ( a_last_ty,  a_rest_tys)  = a_tys. split_last ( ) . unwrap ( ) ; 
345+                     let  b_last_ty = b_tys. last ( ) . unwrap ( ) ; 
346+ 
347+                     // Substitute just the tail field of B., and require that they're equal. 
348+                     let  unsized_a_ty = tcx. mk_tup ( a_rest_tys. iter ( ) . chain ( [ b_last_ty] ) ) ; 
349+                     let  mut  nested_goals = ecx. infcx . eq ( goal. param_env ,  unsized_a_ty,  b_ty) ?; 
350+ 
351+                     // Similar to ADTs, require that the rest of the fields are equal. 
352+                     nested_goals. push ( goal. with ( 
353+                         tcx, 
354+                         ty:: Binder :: dummy ( 
355+                             tcx. mk_trait_ref ( goal. predicate . def_id ( ) ,  [ * a_last_ty,  * b_last_ty] ) , 
356+                         ) , 
357+                     ) ) ; 
358+ 
359+                     ecx. evaluate_all_and_make_canonical_response ( nested_goals) 
360+                 } 
361+                 _ => Err ( NoSolution ) , 
362+             } 
363+         } ) 
364+     } 
365+ 
366+     fn  consider_builtin_dyn_upcast_candidates ( 
367+         ecx :  & mut  EvalCtxt < ' _ ,  ' tcx > , 
368+         goal :  Goal < ' tcx ,  Self > , 
369+     )  -> Vec < CanonicalResponse < ' tcx > >  { 
370+         let  tcx = ecx. tcx ( ) ; 
371+ 
372+         let  a_ty = goal. predicate . self_ty ( ) ; 
373+         let  b_ty = goal. predicate . trait_ref . substs . type_at ( 1 ) ; 
374+         let  ty:: Dynamic ( a_data,  a_region,  ty:: Dyn )  = * a_ty. kind ( )  else  { 
375+             return  vec ! [ ] ; 
376+         } ; 
377+         let  ty:: Dynamic ( b_data,  b_region,  ty:: Dyn )  = * b_ty. kind ( )  else  { 
378+             return  vec ! [ ] ; 
379+         } ; 
380+ 
381+         // All of a's auto traits need to be in b's auto traits. 
382+         let  auto_traits_compatible =
383+             b_data. auto_traits ( ) . all ( |b| a_data. auto_traits ( ) . any ( |a| a == b) ) ; 
384+         if  !auto_traits_compatible { 
385+             return  vec ! [ ] ; 
386+         } 
387+ 
388+         let  mut  unsize_dyn_to_principal = |principal :  Option < ty:: PolyExistentialTraitRef < ' tcx > > | { 
389+             ecx. infcx . probe ( |_| -> Result < _ ,  NoSolution >  { 
390+                 // Require that all of the trait predicates from A match B, except for 
391+                 // the auto traits. We do this by constructing a new A type with B's 
392+                 // auto traits, and equating these types. 
393+                 let  new_a_data = principal
394+                     . into_iter ( ) 
395+                     . map ( |trait_ref| trait_ref. map_bound ( ty:: ExistentialPredicate :: Trait ) ) 
396+                     . chain ( a_data. iter ( ) . filter ( |a| { 
397+                         matches ! ( a. skip_binder( ) ,  ty:: ExistentialPredicate :: Projection ( _) ) 
398+                     } ) ) 
399+                     . chain ( 
400+                         b_data
401+                             . auto_traits ( ) 
402+                             . map ( ty:: ExistentialPredicate :: AutoTrait ) 
403+                             . map ( ty:: Binder :: dummy) , 
404+                     ) ; 
405+                 let  new_a_data = tcx. mk_poly_existential_predicates ( new_a_data) ; 
406+                 let  new_a_ty = tcx. mk_dynamic ( new_a_data,  b_region,  ty:: Dyn ) ; 
407+ 
408+                 // We also require that A's lifetime outlives B's lifetime. 
409+                 let  mut  nested_obligations = ecx. infcx . eq ( goal. param_env ,  new_a_ty,  b_ty) ?; 
410+                 nested_obligations. push ( 
411+                     goal. with ( tcx,  ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region,  b_region) ) ) , 
412+                 ) ; 
413+ 
414+                 ecx. evaluate_all_and_make_canonical_response ( nested_obligations) 
415+             } ) 
416+         } ; 
417+ 
418+         let  mut  responses = vec ! [ ] ; 
419+         // If the principal def ids match (or are both none), then we're not doing 
420+         // trait upcasting. We're just removing auto traits (or shortening the lifetime). 
421+         if  a_data. principal_def_id ( )  == b_data. principal_def_id ( )  { 
422+             if  let  Ok ( response)  = unsize_dyn_to_principal ( a_data. principal ( ) )  { 
423+                 responses. push ( response) ; 
424+             } 
425+         }  else  if  let  Some ( a_principal)  = a_data. principal ( ) 
426+             && let  Some ( b_principal)  = b_data. principal ( ) 
427+         { 
428+             for  super_trait_ref in  supertraits ( tcx,  a_principal. with_self_ty ( tcx,  a_ty) )  { 
429+                 if  super_trait_ref. def_id ( )  != b_principal. def_id ( )  { 
430+                     continue ; 
431+                 } 
432+                 let  erased_trait_ref = super_trait_ref
433+                     . map_bound ( |trait_ref| ty:: ExistentialTraitRef :: erase_self_ty ( tcx,  trait_ref) ) ; 
434+                 if  let  Ok ( response)  = unsize_dyn_to_principal ( Some ( erased_trait_ref) )  { 
435+                     responses. push ( response) ; 
436+                 } 
437+             } 
438+         } 
439+ 
440+         responses
441+     } 
241442} 
242443
243444impl < ' tcx >  EvalCtxt < ' _ ,  ' tcx >  { 
0 commit comments