@@ -4,7 +4,7 @@ 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 ;
@@ -253,57 +253,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
253253 ecx. infcx . probe ( |_| {
254254 match ( a_ty. kind ( ) , b_ty. kind ( ) ) {
255255 // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
256- (
257- & ty:: Dynamic ( a_data, a_region, ty:: Dyn ) ,
258- & ty:: Dynamic ( b_data, b_region, ty:: Dyn ) ,
259- ) => {
260- // All of a's auto traits need to be in b's auto traits.
261- let auto_traits_compatible = b_data
262- . auto_traits ( )
263- . all ( |b| a_data. auto_traits ( ) . any ( |a| a == b) ) ;
264- if !auto_traits_compatible {
265- return Err ( NoSolution ) ;
266- }
267-
268- // If the principal def ids match (or are both none), then we're not doing
269- // trait upcasting. We're just removing auto traits (or shortening the lifetime).
270- if a_data. principal_def_id ( ) == b_data. principal_def_id ( ) {
271- // Require that all of the trait predicates from A match B, except for
272- // the auto traits. We do this by constructing a new A type with B's
273- // auto traits, and equating these types.
274- let new_a_data = a_data
275- . iter ( )
276- . filter ( |a| {
277- matches ! (
278- a. skip_binder( ) ,
279- ty:: ExistentialPredicate :: Trait ( _) | ty:: ExistentialPredicate :: Projection ( _)
280- )
281- } )
282- . chain (
283- b_data
284- . auto_traits ( )
285- . map ( ty:: ExistentialPredicate :: AutoTrait )
286- . map ( ty:: Binder :: dummy) ,
287- ) ;
288- let new_a_data = tcx. mk_poly_existential_predicates ( new_a_data) ;
289- let new_a_ty = tcx. mk_dynamic ( new_a_data, b_region, ty:: Dyn ) ;
290-
291- // We also require that A's lifetime outlives B's lifetime.
292- let mut nested_obligations = ecx. infcx . eq ( goal. param_env , new_a_ty, b_ty) ?;
293- nested_obligations. push ( goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region, b_region) ) ) ) ;
294-
295- ecx. evaluate_all_and_make_canonical_response ( nested_obligations)
296- } else if let Some ( a_principal) = a_data. principal ( )
297- && let Some ( b_principal) = b_data. principal ( )
298- && supertraits ( tcx, a_principal. with_self_ty ( tcx, a_ty) )
299- . any ( |trait_ref| trait_ref. def_id ( ) == b_principal. def_id ( ) )
300- {
301- // FIXME: Intentionally ignoring `need_migrate_deref_output_trait_object` here for now.
302- // Confirm upcasting candidate
303- todo ! ( )
304- } else {
305- Err ( NoSolution )
306- }
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 ) ;
307261 }
308262 // `T` -> `dyn Trait` unsizing
309263 ( _, & ty:: Dynamic ( data, region, ty:: Dyn ) ) => {
@@ -332,10 +286,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
332286 ty:: Binder :: dummy ( tcx. mk_trait_ref ( sized_def_id, [ a_ty] ) ) ,
333287 ) ,
334288 // The type must outlive the lifetime of the `dyn` we're unsizing into.
335- goal. with (
336- tcx,
337- ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_ty, region) ) ,
338- ) ,
289+ goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_ty, region) ) ) ,
339290 ] )
340291 . collect ( ) ;
341292
@@ -413,6 +364,81 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
413364 }
414365 } )
415366 }
367+
368+ fn consider_builtin_dyn_unsize_candidates (
369+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
370+ goal : Goal < ' tcx , Self > ,
371+ ) -> Vec < CanonicalResponse < ' tcx > > {
372+ let tcx = ecx. tcx ( ) ;
373+
374+ let a_ty = goal. predicate . self_ty ( ) ;
375+ let b_ty = goal. predicate . trait_ref . substs . type_at ( 1 ) ;
376+ let ty:: Dynamic ( a_data, a_region, ty:: Dyn ) = * a_ty. kind ( ) else {
377+ return vec ! [ ] ;
378+ } ;
379+ let ty:: Dynamic ( b_data, b_region, ty:: Dyn ) = * b_ty. kind ( ) else {
380+ return vec ! [ ] ;
381+ } ;
382+
383+ // All of a's auto traits need to be in b's auto traits.
384+ let auto_traits_compatible =
385+ b_data. auto_traits ( ) . all ( |b| a_data. auto_traits ( ) . any ( |a| a == b) ) ;
386+ if !auto_traits_compatible {
387+ return vec ! [ ] ;
388+ }
389+
390+ let mut responses = vec ! [ ] ;
391+ let mut unsize_dyn_to_principal = |principal : Option < ty:: PolyExistentialTraitRef < ' tcx > > | {
392+ let _ = ecx. infcx . probe ( |_| -> Result < ( ) , NoSolution > {
393+ // Require that all of the trait predicates from A match B, except for
394+ // the auto traits. We do this by constructing a new A type with B's
395+ // auto traits, and equating these types.
396+ let new_a_data = principal
397+ . into_iter ( )
398+ . map ( |trait_ref| trait_ref. map_bound ( ty:: ExistentialPredicate :: Trait ) )
399+ . chain ( a_data. iter ( ) . filter ( |a| {
400+ matches ! ( a. skip_binder( ) , ty:: ExistentialPredicate :: Projection ( _) )
401+ } ) )
402+ . chain (
403+ b_data
404+ . auto_traits ( )
405+ . map ( ty:: ExistentialPredicate :: AutoTrait )
406+ . map ( ty:: Binder :: dummy) ,
407+ ) ;
408+ let new_a_data = tcx. mk_poly_existential_predicates ( new_a_data) ;
409+ let new_a_ty = tcx. mk_dynamic ( new_a_data, b_region, ty:: Dyn ) ;
410+
411+ // We also require that A's lifetime outlives B's lifetime.
412+ let mut nested_obligations = ecx. infcx . eq ( goal. param_env , new_a_ty, b_ty) ?;
413+ nested_obligations. push (
414+ goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region, b_region) ) ) ,
415+ ) ;
416+
417+ responses. push ( ecx. evaluate_all_and_make_canonical_response ( nested_obligations) ?) ;
418+
419+ Ok ( ( ) )
420+ } ) ;
421+ } ;
422+
423+ // If the principal def ids match (or are both none), then we're not doing
424+ // trait upcasting. We're just removing auto traits (or shortening the lifetime).
425+ if a_data. principal_def_id ( ) == b_data. principal_def_id ( ) {
426+ unsize_dyn_to_principal ( a_data. principal ( ) ) ;
427+ } else if let Some ( a_principal) = a_data. principal ( )
428+ && let Some ( b_principal) = b_data. principal ( )
429+ {
430+ for super_trait_ref in supertraits ( tcx, a_principal. with_self_ty ( tcx, a_ty) ) {
431+ if super_trait_ref. def_id ( ) != b_principal. def_id ( ) {
432+ continue ;
433+ }
434+ let erased_trait_ref = super_trait_ref
435+ . map_bound ( |trait_ref| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) ) ;
436+ unsize_dyn_to_principal ( Some ( erased_trait_ref) ) ;
437+ }
438+ }
439+
440+ responses
441+ }
416442}
417443
418444impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
0 commit comments