@@ -48,20 +48,20 @@ use 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 , SelectionError ,
5252} ;
5353use rustc_middle:: span_bug;
5454use rustc_middle:: ty:: adjustment:: {
5555 Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability , PointerCoercion ,
5656} ;
5757use rustc_middle:: ty:: error:: TypeError ;
5858use rustc_middle:: ty:: visit:: TypeVisitableExt ;
59- use rustc_middle:: ty:: { self , AliasTy , GenericArgsRef , Ty , TyCtxt } ;
60- use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , Span } ;
59+ use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
60+ use rustc_span:: { BytePos , DUMMY_SP , DesugaringKind , ErrorGuaranteed , Span } ;
6161use rustc_trait_selection:: infer:: InferCtxtExt as _;
6262use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
6363use rustc_trait_selection:: traits:: {
64- self , NormalizeExt , ObligationCause , ObligationCauseCode , ObligationCtxt ,
64+ self , FulfillmentErrorCode , NormalizeExt , ObligationCause , ObligationCauseCode , ObligationCtxt ,
6565} ;
6666use smallvec:: { SmallVec , smallvec} ;
6767use tracing:: { debug, instrument} ;
@@ -600,55 +600,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
600600 ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ,
601601 ) ;
602602
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.
609603 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- }
604+ return Err ( TypeError :: Mismatch ) ;
652605 }
653606
654607 // Use a FIFO queue for this custom fulfillment procedure.
@@ -725,17 +678,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
725678 return Err ( TypeError :: Mismatch ) ;
726679 }
727680
728- // Dyn-compatibility violations or miscellaneous .
681+ // Should have been filtered out by the `predicate_may_hold` check .
729682 Err ( err) => {
730- let guar = self . err_ctxt ( ) . report_selection_error (
731- obligation. clone ( ) ,
732- & obligation,
733- & err,
734- ) ;
735- self . fcx . set_tainted_by_errors ( guar) ;
736- // Treat this like an obligation and follow through
737- // with the unsizing - the lack of a coercion should
738- // be silent, as it causes a type mismatch later.
683+ debug ! ( "coerce_unsized: early return - selection error: {err:?}" ) ;
684+ return Err ( TypeError :: Mismatch ) ;
739685 }
740686
741687 Ok ( Some ( impl_source) ) => queue. extend ( impl_source. nested_obligations ( ) ) ,
@@ -1120,6 +1066,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11201066 } )
11211067 }
11221068
1069+ pub ( crate ) fn emit_specialized_coerce_unsize_error (
1070+ & self ,
1071+ span : Span ,
1072+ source : Ty < ' tcx > ,
1073+ target : Ty < ' tcx > ,
1074+ ) -> Option < ErrorGuaranteed > {
1075+ let ocx = ObligationCtxt :: new_with_diagnostics ( self ) ;
1076+ let coerce_unsized_def_id = self . tcx . require_lang_item ( LangItem :: CoerceUnsized , Some ( span) ) ;
1077+ let unsize_def_id = self . tcx . require_lang_item ( LangItem :: Unsize , Some ( span) ) ;
1078+ ocx. register_obligation ( Obligation :: new (
1079+ self . tcx ,
1080+ self . cause ( span, ObligationCauseCode :: Coercion { source, target } ) ,
1081+ self . param_env ,
1082+ ty:: TraitRef :: new ( self . tcx , coerce_unsized_def_id, [ source, target] ) ,
1083+ ) ) ;
1084+
1085+ let mut errors = ocx. select_where_possible ( ) ;
1086+ // Retain the errors that don't mention, but also as a HACK we will adjust their
1087+ // root obligation, too. This is a nasty hack to preserve diagnostic parity that
1088+ // should probably be fixed by emitting better errors for failed `CoerceUnsized`.
1089+ errors. retain_mut ( |err| {
1090+ if matches ! (
1091+ err. code,
1092+ FulfillmentErrorCode :: Select ( SelectionError :: TraitDynIncompatible ( _) ) ,
1093+ ) || err. obligation . predicate . as_trait_clause ( ) . is_none_or ( |trait_clause| {
1094+ trait_clause. def_id ( ) != coerce_unsized_def_id
1095+ && trait_clause. def_id ( ) != unsize_def_id
1096+ } ) {
1097+ err. root_obligation = err. obligation . clone ( ) ;
1098+ true
1099+ } else {
1100+ false
1101+ }
1102+ } ) ;
1103+
1104+ if errors. is_empty ( ) {
1105+ None
1106+ } else {
1107+ let guar = self . err_ctxt ( ) . report_fulfillment_errors ( errors) ;
1108+ self . set_tainted_by_errors ( guar) ;
1109+ Some ( guar)
1110+ }
1111+ }
1112+
11231113 /// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects,
11241114 /// and may return false positives if types are not yet fully constrained by inference.
11251115 ///
@@ -1666,6 +1656,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
16661656 }
16671657 }
16681658 Err ( coercion_error) => {
1659+ if let Some ( _guar) = fcx. emit_specialized_coerce_unsize_error (
1660+ cause. span ,
1661+ expression_ty,
1662+ self . merged_ty ( ) ,
1663+ ) {
1664+ return ;
1665+ }
1666+
16691667 // Mark that we've failed to coerce the types here to suppress
16701668 // any superfluous errors we might encounter while trying to
16711669 // emit or provide suggestions on how to fix the initial error.
0 commit comments