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,9 +364,31 @@ 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 ( ) {
349- res = Err ( infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ) ;
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+
372+ errors = errors
373+ . into_iter ( )
374+ . filter_map ( |err| {
375+ redact_fulfillment_err_for_coerce_pointee (
376+ tcx,
377+ err,
378+ target_pointee,
379+ span,
380+ )
381+ } )
382+ . collect ( ) ;
383+ }
384+ if errors. is_empty ( ) {
385+ res = Err ( tcx. dcx ( ) . span_delayed_bug (
386+ span,
387+ "a specialised CoercePointee error is expected" ,
388+ ) ) ;
389+ } else {
390+ res = Err ( infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ) ;
391+ }
350392 }
351393
352394 // Finally, resolve all regions.
@@ -360,27 +402,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
360402 }
361403}
362404
405+ #[ instrument( level = "debug" , skip( tcx) ) ]
363406pub ( crate ) fn coerce_unsized_info < ' tcx > (
364407 tcx : TyCtxt < ' tcx > ,
365408 impl_did : LocalDefId ,
366409) -> Result < CoerceUnsizedInfo , ErrorGuaranteed > {
367- debug ! ( "compute_coerce_unsized_info(impl_did={:?})" , impl_did) ;
368410 let span = tcx. def_span ( impl_did) ;
369411
370412 let coerce_unsized_trait = tcx. require_lang_item ( LangItem :: CoerceUnsized , Some ( span) ) ;
371413
372414 let unsize_trait = tcx. require_lang_item ( LangItem :: Unsize , Some ( span) ) ;
373415
374416 let source = tcx. type_of ( impl_did) . instantiate_identity ( ) ;
417+ let self_ty = source;
375418 let trait_ref = tcx. impl_trait_ref ( impl_did) . unwrap ( ) . instantiate_identity ( ) ;
376419 assert_eq ! ( trait_ref. def_id, coerce_unsized_trait) ;
377420 let target = trait_ref. args . type_at ( 1 ) ;
378- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)" , source, target) ;
421+ let coerced_ty = target;
422+ debug ! ( "{:?} -> {:?} (bound)" , source, target) ;
379423
380424 let param_env = tcx. param_env ( impl_did) ;
381425 assert ! ( !source. has_escaping_bound_vars( ) ) ;
382426
383- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)" , source, target) ;
427+ debug ! ( "{:?} -> {:?} (free)" , source, target) ;
384428
385429 let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
386430 let cause = ObligationCause :: misc ( span, impl_did) ;
@@ -509,12 +553,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
509553 . collect :: < Vec < _ > > ( ) ;
510554
511555 if diff_fields. is_empty ( ) {
556+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
557+ return Err ( tcx. dcx ( ) . span_delayed_bug (
558+ span,
559+ "a specialised message for CoercePointee is expected" ,
560+ ) ) ;
561+ }
512562 return Err ( tcx. dcx ( ) . emit_err ( errors:: CoerceUnsizedOneField {
513563 span,
514564 trait_name : "CoerceUnsized" ,
515565 note : true ,
516566 } ) ) ;
517567 } else if diff_fields. len ( ) > 1 {
568+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
569+ let spans = diff_fields
570+ . iter ( )
571+ . map ( |& ( idx, _, _) | tcx. def_span ( fields[ idx] . did ) )
572+ . collect ( ) ;
573+ return Err ( tcx. dcx ( ) . emit_err ( errors:: CoercePointeeMultipleTargets {
574+ spans,
575+ diag_trait : "CoerceUnsized" ,
576+ } ) ) ;
577+ }
518578 let item = tcx. hir ( ) . expect_item ( impl_did) ;
519579 let span = if let ItemKind :: Impl ( hir:: Impl { of_trait : Some ( t) , .. } ) = & item. kind {
520580 t. path . span
@@ -547,18 +607,41 @@ pub(crate) fn coerce_unsized_info<'tcx>(
547607 } ;
548608
549609 // Register an obligation for `A: Trait<B>`.
610+ let coerce_pointee_data = if let ty:: Adt ( def, _) = self_ty. kind ( ) {
611+ extract_coerce_pointee_data ( tcx, def. did ( ) )
612+ } else {
613+ None
614+ } ;
550615 let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
551- let cause = traits:: ObligationCause :: misc ( span, impl_did) ;
616+ let cause = traits:: ObligationCause :: misc (
617+ span,
618+ coerce_pointee_data. map_or ( impl_did, |( _, impl_did) | impl_did. expect_local ( ) ) ,
619+ ) ;
552620 let obligation = Obligation :: new (
553621 tcx,
554622 cause,
555623 param_env,
556624 ty:: TraitRef :: new ( tcx, trait_def_id, [ source, target] ) ,
557625 ) ;
558626 ocx. register_obligation ( obligation) ;
559- let errors = ocx. select_all_or_error ( ) ;
627+ let mut errors = ocx. select_all_or_error ( ) ;
560628 if !errors. is_empty ( ) {
561- infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
629+ if let Some ( ( pointee, _) ) = coerce_pointee_data {
630+ let ty:: Adt ( _def, args) = coerced_ty. kind ( ) else { bug ! ( ) } ;
631+ let target_pointee = args. type_at ( pointee) ;
632+ let ty:: Adt ( _def, _) = self_ty. kind ( ) else { bug ! ( ) } ;
633+ errors = errors
634+ . into_iter ( )
635+ . filter_map ( |err| {
636+ redact_fulfillment_err_for_coerce_pointee ( tcx, err, target_pointee, span)
637+ } )
638+ . collect ( ) ;
639+ }
640+ if errors. is_empty ( ) {
641+ tcx. dcx ( ) . span_delayed_bug ( span, "a specialised CoercePointee error is expected" ) ;
642+ } else {
643+ infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
644+ }
562645 }
563646
564647 // Finally, resolve all regions.
0 commit comments