@@ -41,14 +41,14 @@ use rustc_abi::ExternAbi;
4141use rustc_attr_parsing:: InlineAttr ;
4242use rustc_errors:: codes:: * ;
4343use rustc_errors:: { Applicability , Diag , struct_span_code_err} ;
44- use rustc_hir as hir;
4544use rustc_hir:: def_id:: { DefId , LocalDefId } ;
45+ use rustc_hir:: { self as hir, LangItem } ;
4646use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
4747use rustc_infer:: infer:: relate:: RelateResult ;
4848use rustc_infer:: infer:: { Coercion , DefineOpaqueTypes , InferOk , InferResult } ;
4949use rustc_infer:: traits:: {
5050 IfExpressionCause , MatchExpressionArmCause , Obligation , PredicateObligation ,
51- PredicateObligations ,
51+ PredicateObligations , ScrubbedTraitError , TraitEngine ,
5252} ;
5353use rustc_middle:: lint:: in_external_macro;
5454use rustc_middle:: span_bug;
@@ -58,13 +58,14 @@ use rustc_middle::ty::adjustment::{
5858} ;
5959use rustc_middle:: ty:: error:: TypeError ;
6060use rustc_middle:: ty:: visit:: TypeVisitableExt ;
61- use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
61+ use rustc_middle:: ty:: { self , AliasTy , GenericArgsRef , Ty , TyCtxt } ;
6262use rustc_session:: parse:: feature_err;
6363use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Span , sym} ;
6464use rustc_trait_selection:: infer:: InferCtxtExt as _;
6565use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
6666use rustc_trait_selection:: traits:: {
6767 self , NormalizeExt , ObligationCause , ObligationCauseCode , ObligationCtxt ,
68+ StructurallyNormalizeExt ,
6869} ;
6970use smallvec:: { SmallVec , smallvec} ;
7071use tracing:: { debug, instrument} ;
@@ -582,6 +583,64 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
582583
583584 // Create an obligation for `Source: CoerceUnsized<Target>`.
584585 let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
586+ let root_obligation = Obligation :: new (
587+ self . tcx ,
588+ cause. clone ( ) ,
589+ self . fcx . param_env ,
590+ ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ,
591+ ) ;
592+
593+ // If the root `Source: CoerceUnsized<Target>` obligation can't possibly hold,
594+ // we don't have to assume that this is unsizing coercion (it will always lead to an error)
595+ //
596+ // However, we don't want to bail early all the time, since the unholdable obligations
597+ // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id<This = U>`)
598+ // ...
599+ if !self . infcx . predicate_may_hold ( & root_obligation) {
600+ if let Some ( dyn_metadata_adt_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: DynMetadata )
601+ && let Some ( metadata_type_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: Metadata )
602+ {
603+ // ... so we only bail if there may be another way to convert the types.
604+ //
605+ // If both types are raw pointers to a (wrapper over a) trait object,
606+ // this might be a cast like `*const W<dyn Trait> -> *const dyn Trait`.
607+ // So it's better to bail and try that. (even if the cast is not possible, for
608+ // example due to vtables not matching, cast diagnostic will likely still be better)
609+ self . probe ( |_| {
610+ use traits:: TraitEngineExt ;
611+ let mut fulfill_cx = <dyn TraitEngine < ' _ , ScrubbedTraitError < ' _ > > >:: new ( self ) ;
612+ let mut normalize = |ty| {
613+ self . at ( & cause, self . fcx . param_env )
614+ . structurally_normalize ( ty, & mut * fulfill_cx)
615+ } ;
616+
617+ // N.B. use `target`, not `coerce_target` (the latter is a var)
618+ if let & ty:: RawPtr ( source_pointee, _) = coerce_source. kind ( )
619+ && let & ty:: RawPtr ( target_pointee, _) = target. kind ( )
620+ && let Ok ( source_metadata) = normalize ( Ty :: new_alias (
621+ self . tcx ,
622+ ty:: AliasTyKind :: Projection ,
623+ AliasTy :: new ( self . tcx , metadata_type_def_id, [ source_pointee] ) ,
624+ ) )
625+ && source_metadata
626+ . ty_adt_def ( )
627+ . is_some_and ( |d| d. did ( ) == dyn_metadata_adt_def_id)
628+ && let Ok ( target_metadata) = normalize ( Ty :: new_alias (
629+ self . tcx ,
630+ ty:: AliasTyKind :: Projection ,
631+ AliasTy :: new ( self . tcx , metadata_type_def_id, [ target_pointee] ) ,
632+ ) )
633+ && target_metadata
634+ . ty_adt_def ( )
635+ . is_some_and ( |d| d. did ( ) == dyn_metadata_adt_def_id)
636+ {
637+ return Err ( TypeError :: Mismatch ) ;
638+ }
639+
640+ Ok ( ( ) )
641+ } ) ?;
642+ }
643+ }
585644
586645 // Use a FIFO queue for this custom fulfillment procedure.
587646 //
@@ -590,12 +649,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
590649 // and almost never more than 3. By using a SmallVec we avoid an
591650 // allocation, at the (very small) cost of (occasionally) having to
592651 // shift subsequent elements down when removing the front element.
593- let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ Obligation :: new(
594- self . tcx,
595- cause,
596- self . fcx. param_env,
597- ty:: TraitRef :: new( self . tcx, coerce_unsized_did, [ coerce_source, coerce_target] )
598- ) ] ;
652+ let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ root_obligation] ;
599653
600654 let mut has_unsized_tuple_coercion = false ;
601655 let mut has_trait_upcasting_coercion = None ;
0 commit comments