@@ -41,8 +41,8 @@ use rustc_abi::ExternAbi;
41
41
use rustc_attr_parsing:: InlineAttr ;
42
42
use rustc_errors:: codes:: * ;
43
43
use rustc_errors:: { Applicability , Diag , struct_span_code_err} ;
44
- use rustc_hir as hir;
45
44
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
45
+ use rustc_hir:: { self as hir, LangItem } ;
46
46
use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
47
47
use rustc_infer:: infer:: relate:: RelateResult ;
48
48
use rustc_infer:: infer:: { Coercion , DefineOpaqueTypes , InferOk , InferResult } ;
@@ -56,7 +56,7 @@ use rustc_middle::ty::adjustment::{
56
56
} ;
57
57
use rustc_middle:: ty:: error:: TypeError ;
58
58
use rustc_middle:: ty:: visit:: TypeVisitableExt ;
59
- use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
59
+ use rustc_middle:: ty:: { self , AliasTy , GenericArgsRef , Ty , TyCtxt } ;
60
60
use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Span } ;
61
61
use rustc_trait_selection:: infer:: InferCtxtExt as _;
62
62
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
@@ -593,6 +593,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
593
593
594
594
// Create an obligation for `Source: CoerceUnsized<Target>`.
595
595
let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
596
+ let root_obligation = Obligation :: new (
597
+ self . tcx ,
598
+ cause. clone ( ) ,
599
+ self . fcx . param_env ,
600
+ ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ,
601
+ ) ;
602
+
603
+ // If the root `Source: CoerceUnsized<Target>` obligation can't possibly hold,
604
+ // we don't have to assume that this is unsizing coercion (it will always lead to an error)
605
+ //
606
+ // However, we don't want to bail early all the time, since the unholdable obligations
607
+ // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id<This = U>`),
608
+ // so we only bail if there (likely) is another way to convert the types.
609
+ if !self . infcx . predicate_may_hold ( & root_obligation) {
610
+ if let Some ( dyn_metadata_adt_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: DynMetadata )
611
+ && let Some ( metadata_type_def_id) = self . tcx . lang_items ( ) . get ( LangItem :: Metadata )
612
+ {
613
+ self . probe ( |_| {
614
+ let ocx = ObligationCtxt :: new ( & self . infcx ) ;
615
+
616
+ // returns `true` if `<ty as Pointee>::Metadata` is `DynMetadata<_>`
617
+ let has_dyn_trait_metadata = |ty| {
618
+ let metadata_ty: Result < _ , _ > = ocx. structurally_normalize_ty (
619
+ & ObligationCause :: dummy ( ) ,
620
+ self . fcx . param_env ,
621
+ Ty :: new_alias (
622
+ self . tcx ,
623
+ ty:: AliasTyKind :: Projection ,
624
+ AliasTy :: new ( self . tcx , metadata_type_def_id, [ ty] ) ,
625
+ ) ,
626
+ ) ;
627
+
628
+ metadata_ty. is_ok_and ( |metadata_ty| {
629
+ metadata_ty
630
+ . ty_adt_def ( )
631
+ . is_some_and ( |d| d. did ( ) == dyn_metadata_adt_def_id)
632
+ } )
633
+ } ;
634
+
635
+ // If both types are raw pointers to a (wrapper over a) trait object,
636
+ // this might be a cast like `*const W<dyn Trait> -> *const dyn Trait`.
637
+ // So it's better to bail and try that. (even if the cast is not possible, for
638
+ // example due to vtables not matching, cast diagnostic will likely still be better)
639
+ //
640
+ // N.B. use `target`, not `coerce_target` (the latter is a var)
641
+ if let & ty:: RawPtr ( source_pointee, _) = coerce_source. kind ( )
642
+ && let & ty:: RawPtr ( target_pointee, _) = target. kind ( )
643
+ && has_dyn_trait_metadata ( source_pointee)
644
+ && has_dyn_trait_metadata ( target_pointee)
645
+ {
646
+ return Err ( TypeError :: Mismatch ) ;
647
+ }
648
+
649
+ Ok ( ( ) )
650
+ } ) ?;
651
+ }
652
+ }
596
653
597
654
// Use a FIFO queue for this custom fulfillment procedure.
598
655
//
@@ -601,12 +658,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
601
658
// and almost never more than 3. By using a SmallVec we avoid an
602
659
// allocation, at the (very small) cost of (occasionally) having to
603
660
// shift subsequent elements down when removing the front element.
604
- let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ Obligation :: new(
605
- self . tcx,
606
- cause,
607
- self . fcx. param_env,
608
- ty:: TraitRef :: new( self . tcx, coerce_unsized_did, [ coerce_source, coerce_target] )
609
- ) ] ;
661
+ let mut queue: SmallVec < [ PredicateObligation < ' tcx > ; 4 ] > = smallvec ! [ root_obligation] ;
610
662
611
663
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
612
664
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
0 commit comments