@@ -267,11 +267,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
267267 }
268268
269269 // Consider coercing the subtype to a DST
270- //
271- // NOTE: this is wrapped in a `commit_if_ok` because it creates
272- // a "spurious" type variable, and we don't want to have that
273- // type variable in memory if the coercion fails.
274- let unsize = self . commit_if_ok ( |_| self . coerce_unsized ( a, b) ) ;
270+ let unsize = self . coerce_unsized ( a, b) ;
275271 match unsize {
276272 Ok ( _) => {
277273 debug ! ( "coerce: unsize successful" ) ;
@@ -589,8 +585,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
589585 // and call arg (among other positions).
590586 //
591587 // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
592- // That's because these are built-in types for which a core-provided impl
593- // doesn't exist, and for which a user-written impl is invalid.
588+ // That's because one of the following is true.
589+ // - For the built-in types, a core-provided impl doesn't exist and a
590+ // user-written impl is invalid.
591+ // - For enums and unions, they can never be the target of a
592+ // `CoerceUnsized` impl.
593+ // - For structs, they can only be the target of a `CoerceUnsized` impl
594+ // if `LHS` and `RHS` are instances of the same struct type but with
595+ // at least one differing field type. This is impossible when we
596+ // exclude structs with any generic args.
594597 //
595598 // This is technically incomplete when users write impossible bounds like
596599 // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
@@ -619,6 +622,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
619622 | ty:: CoroutineWitness ( _, _)
620623 | ty:: Never
621624 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
625+ ty:: Adt ( adt, args) => match adt. adt_kind ( ) {
626+ ty:: AdtKind :: Enum | ty:: AdtKind :: Union => return Err ( TypeError :: Mismatch ) ,
627+ ty:: AdtKind :: Struct if args. is_empty ( ) => return Err ( TypeError :: Mismatch ) ,
628+ _ => { }
629+ } ,
622630 _ => { }
623631 }
624632 // `&str: CoerceUnsized<&str>` does not hold but is encountered frequently
@@ -642,85 +650,92 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
642650 // a DST unless we have to. This currently comes out in the wash since
643651 // we can't unify [T] with U. But to properly support DST, we need to allow
644652 // that, at which point we will need extra checks on the target here.
653+ //
654+ // NOTE: this is wrapped in a `commit_if_ok` because it creates
655+ // a "spurious" type variable, and we don't want to have that
656+ // type variable in memory if the coercion fails.
657+ self . commit_if_ok ( |_| {
658+ // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
659+ let reborrow = match ( source. kind ( ) , target. kind ( ) ) {
660+ ( & ty:: Ref ( _, ty_a, mutbl_a) , & ty:: Ref ( _, _, mutbl_b) ) => {
661+ coerce_mutbls ( mutbl_a, mutbl_b) ?;
645662
646- // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
647- let reborrow = match ( source. kind ( ) , target. kind ( ) ) {
648- ( & ty:: Ref ( _, ty_a, mutbl_a) , & ty:: Ref ( _, _, mutbl_b) ) => {
649- coerce_mutbls ( mutbl_a, mutbl_b) ?;
650-
651- let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
652- let r_borrow = self . next_region_var ( coercion) ;
653-
654- // We don't allow two-phase borrows here, at least for initial
655- // implementation. If it happens that this coercion is a function argument,
656- // the reborrow in coerce_borrowed_ptr will pick it up.
657- let mutbl = AutoBorrowMutability :: new ( mutbl_b, AllowTwoPhase :: No ) ;
658-
659- Some ( (
660- Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
661- Adjustment {
662- kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
663- target : Ty :: new_ref ( self . tcx , r_borrow, ty_a, mutbl_b) ,
664- } ,
665- ) )
666- }
667- ( & ty:: Ref ( _, ty_a, mt_a) , & ty:: RawPtr ( _, mt_b) ) => {
668- coerce_mutbls ( mt_a, mt_b) ?;
669-
670- Some ( (
671- Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
672- Adjustment {
673- kind : Adjust :: Borrow ( AutoBorrow :: RawPtr ( mt_b) ) ,
674- target : Ty :: new_ptr ( self . tcx , ty_a, mt_b) ,
675- } ,
676- ) )
677- }
678- _ => None ,
679- } ;
680- let coerce_source = reborrow. as_ref ( ) . map_or ( source, |( _, r) | r. target ) ;
681-
682- // Setup either a subtyping or a LUB relationship between
683- // the `CoerceUnsized` target type and the expected type.
684- // We only have the latter, so we use an inference variable
685- // for the former and let type inference do the rest.
686- let coerce_target = self . next_ty_var ( self . cause . span ) ;
687-
688- let mut coercion = self . unify_and (
689- coerce_target,
690- target,
691- reborrow. map ( |( deref, autoref) | [ deref, autoref] ) . into_flat_iter ( ) ,
692- Adjust :: Pointer ( PointerCoercion :: Unsize ) ,
693- ForceLeakCheck :: No ,
694- ) ?;
695-
696- // Create an obligation for `Source: CoerceUnsized<Target>`.
697- let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
698- let pred = ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ;
699- let obligation = Obligation :: new ( self . tcx , cause, self . fcx . param_env , pred) ;
700-
701- if self . next_trait_solver ( ) {
702- coercion. obligations . push ( obligation) ;
663+ let coercion = RegionVariableOrigin :: Coercion ( self . cause . span ) ;
664+ let r_borrow = self . next_region_var ( coercion) ;
665+
666+ // We don't allow two-phase borrows here, at least for initial
667+ // implementation. If it happens that this coercion is a function argument,
668+ // the reborrow in coerce_borrowed_ptr will pick it up.
669+ let mutbl = AutoBorrowMutability :: new ( mutbl_b, AllowTwoPhase :: No ) ;
670+
671+ Some ( (
672+ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
673+ Adjustment {
674+ kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
675+ target : Ty :: new_ref ( self . tcx , r_borrow, ty_a, mutbl_b) ,
676+ } ,
677+ ) )
678+ }
679+ ( & ty:: Ref ( _, ty_a, mt_a) , & ty:: RawPtr ( _, mt_b) ) => {
680+ coerce_mutbls ( mt_a, mt_b) ?;
681+
682+ Some ( (
683+ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
684+ Adjustment {
685+ kind : Adjust :: Borrow ( AutoBorrow :: RawPtr ( mt_b) ) ,
686+ target : Ty :: new_ptr ( self . tcx , ty_a, mt_b) ,
687+ } ,
688+ ) )
689+ }
690+ _ => None ,
691+ } ;
692+ let coerce_source = reborrow. as_ref ( ) . map_or ( source, |( _, r) | r. target ) ;
693+
694+ // Setup either a subtyping or a LUB relationship between
695+ // the `CoerceUnsized` target type and the expected type.
696+ // We only have the latter, so we use an inference variable
697+ // for the former and let type inference do the rest.
698+ let coerce_target = self . next_ty_var ( self . cause . span ) ;
699+
700+ let mut coercion = self . unify_and (
701+ coerce_target,
702+ target,
703+ reborrow. map ( |( deref, autoref) | [ deref, autoref] ) . into_flat_iter ( ) ,
704+ Adjust :: Pointer ( PointerCoercion :: Unsize ) ,
705+ ForceLeakCheck :: No ,
706+ ) ?;
703707
704- if self
705- . infcx
706- . visit_proof_tree (
707- Goal :: new ( self . tcx , self . param_env , pred) ,
708- & mut CoerceVisitor { fcx : self . fcx , span : self . cause . span , errored : false } ,
709- )
710- . is_break ( )
711- {
712- return Err ( TypeError :: Mismatch ) ;
708+ // Create an obligation for `Source: CoerceUnsized<Target>`.
709+ let cause =
710+ self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
711+ let pred =
712+ ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ;
713+ let obligation = Obligation :: new ( self . tcx , cause, self . fcx . param_env , pred) ;
714+
715+ if self . next_trait_solver ( ) {
716+ coercion. obligations . push ( obligation) ;
717+
718+ if self
719+ . infcx
720+ . visit_proof_tree (
721+ Goal :: new ( self . tcx , self . param_env , pred) ,
722+ & mut CoerceVisitor { fcx : self . fcx , span : self . cause . span , errored : false } ,
723+ )
724+ . is_break ( )
725+ {
726+ return Err ( TypeError :: Mismatch ) ;
727+ }
728+ } else {
729+ self . coerce_unsized_old_solver (
730+ obligation,
731+ & mut coercion,
732+ coerce_unsized_did,
733+ unsize_did,
734+ ) ?;
713735 }
714- } else {
715- self . coerce_unsized_old_solver (
716- obligation,
717- & mut coercion,
718- coerce_unsized_did,
719- unsize_did,
720- ) ?;
721- }
722736
723- Ok ( coercion)
737+ Ok ( coercion)
738+ } )
724739 }
725740
726741 fn coerce_unsized_old_solver (
0 commit comments