11//! Check properties that are required by built-in traits and set
22//! up data structures required by type-checking/codegen.
33
4+ mod diagnostics;
5+
46use std:: assert_matches:: assert_matches;
57use std:: collections:: BTreeMap ;
68
9+ use diagnostics:: { extract_coerce_pointee_data, redact_fulfillment_err_for_coerce_pointee} ;
710use rustc_data_structures:: fx:: FxHashSet ;
811use rustc_errors:: { ErrorGuaranteed , MultiSpan } ;
912use rustc_hir as hir;
@@ -12,6 +15,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1215use rustc_hir:: lang_items:: LangItem ;
1316use rustc_infer:: infer:: { self , RegionResolutionError , TyCtxtInferExt } ;
1417use rustc_infer:: traits:: Obligation ;
18+ use rustc_middle:: bug;
1519use rustc_middle:: ty:: adjustment:: CoerceUnsizedInfo ;
1620use rustc_middle:: ty:: print:: PrintTraitRefExt as _;
1721use rustc_middle:: ty:: {
@@ -24,7 +28,7 @@ use rustc_trait_selection::traits::misc::{
2428 type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
2529} ;
2630use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCtxt } ;
27- use tracing:: debug;
31+ use tracing:: { debug, instrument } ;
2832
2933use crate :: errors;
3034
@@ -187,10 +191,10 @@ fn visit_implementation_of_const_param_ty(
187191 }
188192}
189193
194+ #[ instrument( level = "debug" , skip( checker) , fields( impl_did = ?checker. impl_def_id) ) ]
190195fn visit_implementation_of_coerce_unsized ( checker : & Checker < ' _ > ) -> Result < ( ) , ErrorGuaranteed > {
191196 let tcx = checker. tcx ;
192197 let impl_did = checker. impl_def_id ;
193- debug ! ( "visit_implementation_of_coerce_unsized: impl_did={:?}" , impl_did) ;
194198
195199 // Just compute this for the side-effects, in particular reporting
196200 // errors; other parts of the code may demand it for the info of
@@ -199,11 +203,11 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
199203 tcx. at ( span) . ensure_ok ( ) . coerce_unsized_info ( impl_did)
200204}
201205
206+ #[ instrument( level = "debug" , skip( checker) , fields( impl_did = ?checker. impl_def_id) ) ]
202207fn visit_implementation_of_dispatch_from_dyn ( checker : & Checker < ' _ > ) -> Result < ( ) , ErrorGuaranteed > {
203208 let tcx = checker. tcx ;
204209 let impl_did = checker. impl_def_id ;
205210 let trait_ref = checker. impl_header . trait_ref . instantiate_identity ( ) ;
206- debug ! ( "visit_implementation_of_dispatch_from_dyn: impl_did={:?}" , impl_did) ;
207211
208212 let span = tcx. def_span ( impl_did) ;
209213
@@ -307,29 +311,45 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
307311 . collect :: < Vec < _ > > ( ) ;
308312
309313 if coerced_fields. is_empty ( ) {
310- res = Err ( tcx. dcx ( ) . emit_err ( errors:: DispatchFromDynSingle {
311- span,
312- trait_name : "DispatchFromDyn" ,
313- note : true ,
314- } ) ) ;
314+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
315+ res = Err ( tcx. dcx ( ) . span_delayed_bug (
316+ span,
317+ "a specialised message for CoercePointee is expected" ,
318+ ) ) ;
319+ } else {
320+ res = Err ( tcx. dcx ( ) . emit_err ( errors:: DispatchFromDynSingle {
321+ span,
322+ trait_name : "DispatchFromDyn" ,
323+ note : true ,
324+ } ) ) ;
325+ }
315326 } else if coerced_fields. len ( ) > 1 {
316- res = Err ( tcx. dcx ( ) . emit_err ( errors:: DispatchFromDynMulti {
317- span,
318- coercions_note : true ,
319- number : coerced_fields. len ( ) ,
320- coercions : coerced_fields
321- . iter ( )
322- . map ( |field| {
323- format ! (
324- "`{}` (`{}` to `{}`)" ,
325- field. name,
326- field. ty( tcx, args_a) ,
327- field. ty( tcx, args_b) ,
328- )
329- } )
330- . collect :: < Vec < _ > > ( )
331- . join ( ", " ) ,
332- } ) ) ;
327+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
328+ let spans =
329+ coerced_fields. iter ( ) . map ( |field| tcx. def_span ( field. did ) ) . collect ( ) ;
330+ res = Err ( tcx. dcx ( ) . emit_err ( errors:: CoercePointeeMultipleTargets {
331+ spans,
332+ diag_trait : "DispatchFromDyn" ,
333+ } ) ) ;
334+ } else {
335+ res = Err ( tcx. dcx ( ) . emit_err ( errors:: DispatchFromDynMulti {
336+ span,
337+ coercions_note : true ,
338+ number : coerced_fields. len ( ) ,
339+ coercions : coerced_fields
340+ . iter ( )
341+ . map ( |field| {
342+ format ! (
343+ "`{}` (`{}` to `{}`)" ,
344+ field. name,
345+ field. ty( tcx, args_a) ,
346+ field. ty( tcx, args_b) ,
347+ )
348+ } )
349+ . collect :: < Vec < _ > > ( )
350+ . join ( ", " ) ,
351+ } ) ) ;
352+ }
333353 } else {
334354 let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
335355 for field in coerced_fields {
@@ -344,8 +364,26 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
344364 ) ,
345365 ) ) ;
346366 }
347- let errors = ocx. select_all_or_error ( ) ;
367+ let mut errors = ocx. select_all_or_error ( ) ;
348368 if !errors. is_empty ( ) {
369+ if let Some ( ( pointee_idx, _) ) = extract_coerce_pointee_data ( tcx, def_a. did ( ) ) {
370+ let target_pointee = args_b. type_at ( pointee_idx) ;
371+ let source_pointee = args_a. type_at ( pointee_idx) ;
372+ let new_pointee =
373+ diagnostics:: unsized_type_for_coerce_pointee ( tcx, source_pointee) ;
374+
375+ errors = errors
376+ . into_iter ( )
377+ . map ( |err| {
378+ redact_fulfillment_err_for_coerce_pointee (
379+ tcx,
380+ err,
381+ target_pointee,
382+ new_pointee,
383+ )
384+ } )
385+ . collect ( ) ;
386+ }
349387 res = Err ( infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ) ;
350388 }
351389
@@ -360,27 +398,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
360398 }
361399}
362400
401+ #[ instrument( level = "debug" , skip( tcx) ) ]
363402pub ( crate ) fn coerce_unsized_info < ' tcx > (
364403 tcx : TyCtxt < ' tcx > ,
365404 impl_did : LocalDefId ,
366405) -> Result < CoerceUnsizedInfo , ErrorGuaranteed > {
367- debug ! ( "compute_coerce_unsized_info(impl_did={:?})" , impl_did) ;
368406 let span = tcx. def_span ( impl_did) ;
369407
370408 let coerce_unsized_trait = tcx. require_lang_item ( LangItem :: CoerceUnsized , Some ( span) ) ;
371409
372410 let unsize_trait = tcx. require_lang_item ( LangItem :: Unsize , Some ( span) ) ;
373411
374412 let source = tcx. type_of ( impl_did) . instantiate_identity ( ) ;
413+ let self_ty = source;
375414 let trait_ref = tcx. impl_trait_ref ( impl_did) . unwrap ( ) . instantiate_identity ( ) ;
376415 assert_eq ! ( trait_ref. def_id, coerce_unsized_trait) ;
377416 let target = trait_ref. args . type_at ( 1 ) ;
378- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)" , source, target) ;
417+ let coerced_ty = target;
418+ debug ! ( "{:?} -> {:?} (bound)" , source, target) ;
379419
380420 let param_env = tcx. param_env ( impl_did) ;
381421 assert ! ( !source. has_escaping_bound_vars( ) ) ;
382422
383- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)" , source, target) ;
423+ debug ! ( "{:?} -> {:?} (free)" , source, target) ;
384424
385425 let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
386426 let cause = ObligationCause :: misc ( span, impl_did) ;
@@ -509,12 +549,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
509549 . collect :: < Vec < _ > > ( ) ;
510550
511551 if diff_fields. is_empty ( ) {
552+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
553+ return Err ( tcx. dcx ( ) . span_delayed_bug (
554+ span,
555+ "a specialised message for CoercePointee is expected" ,
556+ ) ) ;
557+ }
512558 return Err ( tcx. dcx ( ) . emit_err ( errors:: CoerceUnsizedOneField {
513559 span,
514560 trait_name : "CoerceUnsized" ,
515561 note : true ,
516562 } ) ) ;
517563 } else if diff_fields. len ( ) > 1 {
564+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
565+ let spans = diff_fields
566+ . iter ( )
567+ . map ( |& ( idx, _, _) | tcx. def_span ( fields[ idx] . did ) )
568+ . collect ( ) ;
569+ return Err ( tcx. dcx ( ) . emit_err ( errors:: CoercePointeeMultipleTargets {
570+ spans,
571+ diag_trait : "CoerceUnsized" ,
572+ } ) ) ;
573+ }
518574 let item = tcx. hir ( ) . expect_item ( impl_did) ;
519575 let span = if let ItemKind :: Impl ( hir:: Impl { of_trait : Some ( t) , .. } ) = & item. kind {
520576 t. path . span
@@ -547,17 +603,38 @@ pub(crate) fn coerce_unsized_info<'tcx>(
547603 } ;
548604
549605 // Register an obligation for `A: Trait<B>`.
606+ let coerce_pointee_data = if let ty:: Adt ( def, _) = self_ty. kind ( ) {
607+ extract_coerce_pointee_data ( tcx, def. did ( ) )
608+ } else {
609+ None
610+ } ;
550611 let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
551- let cause = traits:: ObligationCause :: misc ( span, impl_did) ;
612+ let cause = traits:: ObligationCause :: misc (
613+ span,
614+ coerce_pointee_data. map_or ( impl_did, |( _, impl_did) | impl_did. expect_local ( ) ) ,
615+ ) ;
552616 let obligation = Obligation :: new (
553617 tcx,
554618 cause,
555619 param_env,
556620 ty:: TraitRef :: new ( tcx, trait_def_id, [ source, target] ) ,
557621 ) ;
558622 ocx. register_obligation ( obligation) ;
559- let errors = ocx. select_all_or_error ( ) ;
623+ let mut errors = ocx. select_all_or_error ( ) ;
560624 if !errors. is_empty ( ) {
625+ if let Some ( ( pointee, _) ) = coerce_pointee_data {
626+ let ty:: Adt ( _def, args) = coerced_ty. kind ( ) else { bug ! ( ) } ;
627+ let target_pointee = args. type_at ( pointee) ;
628+ let ty:: Adt ( _def, args) = self_ty. kind ( ) else { bug ! ( ) } ;
629+ let source_pointee = args. type_at ( pointee) ;
630+ let new_pointee = diagnostics:: unsized_type_for_coerce_pointee ( tcx, source_pointee) ;
631+ errors = errors
632+ . into_iter ( )
633+ . map ( |err| {
634+ redact_fulfillment_err_for_coerce_pointee ( tcx, err, target_pointee, new_pointee)
635+ } )
636+ . collect ( ) ;
637+ }
561638 infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
562639 }
563640
0 commit comments