@@ -48,20 +48,20 @@ use rustc_infer::infer::relate::RelateResult;
48
48
use rustc_infer:: infer:: { Coercion , DefineOpaqueTypes , InferOk , InferResult } ;
49
49
use rustc_infer:: traits:: {
50
50
IfExpressionCause , MatchExpressionArmCause , Obligation , PredicateObligation ,
51
- PredicateObligations ,
51
+ PredicateObligations , SelectionError ,
52
52
} ;
53
53
use rustc_middle:: span_bug;
54
54
use rustc_middle:: ty:: adjustment:: {
55
55
Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability , PointerCoercion ,
56
56
} ;
57
57
use rustc_middle:: ty:: error:: TypeError ;
58
58
use 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 } ;
61
61
use rustc_trait_selection:: infer:: InferCtxtExt as _;
62
62
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
63
63
use rustc_trait_selection:: traits:: {
64
- self , NormalizeExt , ObligationCause , ObligationCauseCode , ObligationCtxt ,
64
+ self , FulfillmentErrorCode , NormalizeExt , ObligationCause , ObligationCauseCode , ObligationCtxt ,
65
65
} ;
66
66
use smallvec:: { SmallVec , smallvec} ;
67
67
use tracing:: { debug, instrument} ;
@@ -600,55 +600,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
600
600
ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ,
601
601
) ;
602
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
603
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 ) ;
652
605
}
653
606
654
607
// Use a FIFO queue for this custom fulfillment procedure.
@@ -725,17 +678,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
725
678
return Err ( TypeError :: Mismatch ) ;
726
679
}
727
680
728
- // Dyn-compatibility violations or miscellaneous .
681
+ // Should have been filtered out by the `predicate_may_hold` check .
729
682
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 ) ;
739
685
}
740
686
741
687
Ok ( Some ( impl_source) ) => queue. extend ( impl_source. nested_obligations ( ) ) ,
@@ -1120,6 +1066,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1120
1066
} )
1121
1067
}
1122
1068
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
+
1123
1113
/// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects,
1124
1114
/// and may return false positives if types are not yet fully constrained by inference.
1125
1115
///
@@ -1666,6 +1656,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
1666
1656
}
1667
1657
}
1668
1658
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
+
1669
1667
// Mark that we've failed to coerce the types here to suppress
1670
1668
// any superfluous errors we might encounter while trying to
1671
1669
// emit or provide suggestions on how to fix the initial error.
0 commit comments