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,19 +15,20 @@ 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:: {
1822 self , Ty , TyCtxt , TypeVisitableExt , TypingMode , suggest_constraining_type_params,
1923} ;
20- use rustc_span:: { DUMMY_SP , Span } ;
24+ use rustc_span:: { DUMMY_SP , Span , Symbol } ;
2125use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
2226use rustc_trait_selection:: traits:: misc:: {
2327 ConstParamTyImplementationError , CopyImplementationError , InfringingFieldsReason ,
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 {
@@ -343,8 +363,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
343363 ] ) ,
344364 ) ) ;
345365 }
346- let errors = ocx. select_all_or_error ( ) ;
366+ let mut errors = ocx. select_all_or_error ( ) ;
347367 if !errors. is_empty ( ) {
368+ if let Some ( ( pointee_idx, _) ) = extract_coerce_pointee_data ( tcx, def_a. did ( ) ) {
369+ let target_pointee = args_b. type_at ( pointee_idx) ;
370+ let source_pointee = args_a. type_at ( pointee_idx) ;
371+ let new_pointee = Ty :: new_param (
372+ tcx,
373+ u32:: MAX ,
374+ Symbol :: intern ( & format ! ( "{source_pointee} {{coerced}}" ) ) ,
375+ ) ;
376+
377+ errors = errors
378+ . into_iter ( )
379+ . map ( |err| {
380+ redact_fulfillment_err_for_coerce_pointee (
381+ tcx,
382+ err,
383+ target_pointee,
384+ new_pointee,
385+ )
386+ } )
387+ . collect ( ) ;
388+ }
348389 res = Err ( infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ) ;
349390 }
350391
@@ -359,27 +400,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
359400 }
360401}
361402
403+ #[ instrument( level = "debug" , skip( tcx) ) ]
362404pub ( crate ) fn coerce_unsized_info < ' tcx > (
363405 tcx : TyCtxt < ' tcx > ,
364406 impl_did : LocalDefId ,
365407) -> Result < CoerceUnsizedInfo , ErrorGuaranteed > {
366- debug ! ( "compute_coerce_unsized_info(impl_did={:?})" , impl_did) ;
367408 let span = tcx. def_span ( impl_did) ;
368409
369410 let coerce_unsized_trait = tcx. require_lang_item ( LangItem :: CoerceUnsized , Some ( span) ) ;
370411
371412 let unsize_trait = tcx. require_lang_item ( LangItem :: Unsize , Some ( span) ) ;
372413
373414 let source = tcx. type_of ( impl_did) . instantiate_identity ( ) ;
415+ let self_ty = source;
374416 let trait_ref = tcx. impl_trait_ref ( impl_did) . unwrap ( ) . instantiate_identity ( ) ;
375417 assert_eq ! ( trait_ref. def_id, coerce_unsized_trait) ;
376418 let target = trait_ref. args . type_at ( 1 ) ;
377- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)" , source, target) ;
419+ let coerced_ty = target;
420+ debug ! ( "{:?} -> {:?} (bound)" , source, target) ;
378421
379422 let param_env = tcx. param_env ( impl_did) ;
380423 assert ! ( !source. has_escaping_bound_vars( ) ) ;
381424
382- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)" , source, target) ;
425+ debug ! ( "{:?} -> {:?} (free)" , source, target) ;
383426
384427 let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
385428 let cause = ObligationCause :: misc ( span, impl_did) ;
@@ -508,12 +551,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
508551 . collect :: < Vec < _ > > ( ) ;
509552
510553 if diff_fields. is_empty ( ) {
554+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
555+ return Err ( tcx. dcx ( ) . span_delayed_bug (
556+ span,
557+ "a specialised message for CoercePointee is expected" ,
558+ ) ) ;
559+ }
511560 return Err ( tcx. dcx ( ) . emit_err ( errors:: CoerceUnsizedOneField {
512561 span,
513562 trait_name : "CoerceUnsized" ,
514563 note : true ,
515564 } ) ) ;
516565 } else if diff_fields. len ( ) > 1 {
566+ if extract_coerce_pointee_data ( tcx, def_a. did ( ) ) . is_some ( ) {
567+ let spans = diff_fields
568+ . iter ( )
569+ . map ( |& ( idx, _, _) | tcx. def_span ( fields[ idx] . did ) )
570+ . collect ( ) ;
571+ return Err ( tcx. dcx ( ) . emit_err ( errors:: CoercePointeeMultipleTargets {
572+ spans,
573+ diag_trait : "CoerceUnsized" ,
574+ } ) ) ;
575+ }
517576 let item = tcx. hir ( ) . expect_item ( impl_did) ;
518577 let span = if let ItemKind :: Impl ( hir:: Impl { of_trait : Some ( t) , .. } ) = & item. kind {
519578 t. path . span
@@ -546,17 +605,42 @@ pub(crate) fn coerce_unsized_info<'tcx>(
546605 } ;
547606
548607 // Register an obligation for `A: Trait<B>`.
608+ let coerce_pointee_data = if let ty:: Adt ( def, _) = self_ty. kind ( ) {
609+ extract_coerce_pointee_data ( tcx, def. did ( ) )
610+ } else {
611+ None
612+ } ;
549613 let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
550- let cause = traits:: ObligationCause :: misc ( span, impl_did) ;
614+ let cause = traits:: ObligationCause :: misc (
615+ span,
616+ coerce_pointee_data. map_or ( impl_did, |( _, impl_did) | impl_did. expect_local ( ) ) ,
617+ ) ;
551618 let obligation = Obligation :: new (
552619 tcx,
553620 cause,
554621 param_env,
555622 ty:: TraitRef :: new ( tcx, trait_def_id, [ source, target] ) ,
556623 ) ;
557624 ocx. register_obligation ( obligation) ;
558- let errors = ocx. select_all_or_error ( ) ;
625+ let mut errors = ocx. select_all_or_error ( ) ;
559626 if !errors. is_empty ( ) {
627+ if let Some ( ( pointee, _) ) = coerce_pointee_data {
628+ let ty:: Adt ( _def, args) = coerced_ty. kind ( ) else { bug ! ( ) } ;
629+ let target_pointee = args. type_at ( pointee) ;
630+ let ty:: Adt ( _def, args) = self_ty. kind ( ) else { bug ! ( ) } ;
631+ let source_pointee = args. type_at ( pointee) ;
632+ let new_pointee = Ty :: new_param (
633+ tcx,
634+ u32:: MAX ,
635+ Symbol :: intern ( & format ! ( "{source_pointee} {{coerced}}" ) ) ,
636+ ) ;
637+ errors = errors
638+ . into_iter ( )
639+ . map ( |err| {
640+ redact_fulfillment_err_for_coerce_pointee ( tcx, err, target_pointee, new_pointee)
641+ } )
642+ . collect ( ) ;
643+ }
560644 infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
561645 }
562646
0 commit comments