1
1
//! Check properties that are required by built-in traits and set
2
2
//! up data structures required by type-checking/codegen.
3
3
4
+ mod diagnostics;
5
+
4
6
use std:: assert_matches:: assert_matches;
5
7
use std:: collections:: BTreeMap ;
6
8
9
+ use diagnostics:: { extract_coerce_pointee_data, redact_fulfillment_err_for_coerce_pointee} ;
7
10
use rustc_data_structures:: fx:: FxHashSet ;
8
11
use rustc_errors:: { ErrorGuaranteed , MultiSpan } ;
9
12
use rustc_hir as hir;
@@ -12,6 +15,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
12
15
use rustc_hir:: lang_items:: LangItem ;
13
16
use rustc_infer:: infer:: { self , RegionResolutionError , TyCtxtInferExt } ;
14
17
use rustc_infer:: traits:: Obligation ;
18
+ use rustc_middle:: bug;
15
19
use rustc_middle:: ty:: adjustment:: CoerceUnsizedInfo ;
16
20
use rustc_middle:: ty:: print:: PrintTraitRefExt as _;
17
21
use rustc_middle:: ty:: {
@@ -24,7 +28,7 @@ use rustc_trait_selection::traits::misc::{
24
28
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
25
29
} ;
26
30
use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCtxt } ;
27
- use tracing:: debug;
31
+ use tracing:: { debug, instrument } ;
28
32
29
33
use crate :: errors;
30
34
@@ -187,10 +191,10 @@ fn visit_implementation_of_const_param_ty(
187
191
}
188
192
}
189
193
194
+ #[ instrument( level = "debug" , skip( checker) , fields( impl_did = ?checker. impl_def_id) ) ]
190
195
fn visit_implementation_of_coerce_unsized ( checker : & Checker < ' _ > ) -> Result < ( ) , ErrorGuaranteed > {
191
196
let tcx = checker. tcx ;
192
197
let impl_did = checker. impl_def_id ;
193
- debug ! ( "visit_implementation_of_coerce_unsized: impl_did={:?}" , impl_did) ;
194
198
195
199
// Just compute this for the side-effects, in particular reporting
196
200
// 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
199
203
tcx. at ( span) . ensure_ok ( ) . coerce_unsized_info ( impl_did)
200
204
}
201
205
206
+ #[ instrument( level = "debug" , skip( checker) , fields( impl_did = ?checker. impl_def_id) ) ]
202
207
fn visit_implementation_of_dispatch_from_dyn ( checker : & Checker < ' _ > ) -> Result < ( ) , ErrorGuaranteed > {
203
208
let tcx = checker. tcx ;
204
209
let impl_did = checker. impl_def_id ;
205
210
let trait_ref = checker. impl_header . trait_ref . instantiate_identity ( ) ;
206
- debug ! ( "visit_implementation_of_dispatch_from_dyn: impl_did={:?}" , impl_did) ;
207
211
208
212
let span = tcx. def_span ( impl_did) ;
209
213
@@ -307,29 +311,45 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
307
311
. collect :: < Vec < _ > > ( ) ;
308
312
309
313
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
+ }
315
326
} 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
+ }
333
353
} else {
334
354
let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
335
355
for field in coerced_fields {
@@ -344,8 +364,26 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
344
364
) ,
345
365
) ) ;
346
366
}
347
- let errors = ocx. select_all_or_error ( ) ;
367
+ let mut errors = ocx. select_all_or_error ( ) ;
348
368
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
+ }
349
387
res = Err ( infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ) ;
350
388
}
351
389
@@ -360,27 +398,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
360
398
}
361
399
}
362
400
401
+ #[ instrument( level = "debug" , skip( tcx) ) ]
363
402
pub ( crate ) fn coerce_unsized_info < ' tcx > (
364
403
tcx : TyCtxt < ' tcx > ,
365
404
impl_did : LocalDefId ,
366
405
) -> Result < CoerceUnsizedInfo , ErrorGuaranteed > {
367
- debug ! ( "compute_coerce_unsized_info(impl_did={:?})" , impl_did) ;
368
406
let span = tcx. def_span ( impl_did) ;
369
407
370
408
let coerce_unsized_trait = tcx. require_lang_item ( LangItem :: CoerceUnsized , Some ( span) ) ;
371
409
372
410
let unsize_trait = tcx. require_lang_item ( LangItem :: Unsize , Some ( span) ) ;
373
411
374
412
let source = tcx. type_of ( impl_did) . instantiate_identity ( ) ;
413
+ let self_ty = source;
375
414
let trait_ref = tcx. impl_trait_ref ( impl_did) . unwrap ( ) . instantiate_identity ( ) ;
376
415
assert_eq ! ( trait_ref. def_id, coerce_unsized_trait) ;
377
416
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) ;
379
419
380
420
let param_env = tcx. param_env ( impl_did) ;
381
421
assert ! ( !source. has_escaping_bound_vars( ) ) ;
382
422
383
- debug ! ( "visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)" , source, target) ;
423
+ debug ! ( "{:?} -> {:?} (free)" , source, target) ;
384
424
385
425
let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
386
426
let cause = ObligationCause :: misc ( span, impl_did) ;
@@ -509,12 +549,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
509
549
. collect :: < Vec < _ > > ( ) ;
510
550
511
551
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
+ }
512
558
return Err ( tcx. dcx ( ) . emit_err ( errors:: CoerceUnsizedOneField {
513
559
span,
514
560
trait_name : "CoerceUnsized" ,
515
561
note : true ,
516
562
} ) ) ;
517
563
} 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
+ }
518
574
let item = tcx. hir ( ) . expect_item ( impl_did) ;
519
575
let span = if let ItemKind :: Impl ( hir:: Impl { of_trait : Some ( t) , .. } ) = & item. kind {
520
576
t. path . span
@@ -547,17 +603,38 @@ pub(crate) fn coerce_unsized_info<'tcx>(
547
603
} ;
548
604
549
605
// 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
+ } ;
550
611
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
+ ) ;
552
616
let obligation = Obligation :: new (
553
617
tcx,
554
618
cause,
555
619
param_env,
556
620
ty:: TraitRef :: new ( tcx, trait_def_id, [ source, target] ) ,
557
621
) ;
558
622
ocx. register_obligation ( obligation) ;
559
- let errors = ocx. select_all_or_error ( ) ;
623
+ let mut errors = ocx. select_all_or_error ( ) ;
560
624
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
+ }
561
638
infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
562
639
}
563
640
0 commit comments