@@ -53,12 +53,13 @@ use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
53
53
use crate :: infer;
54
54
use crate :: infer:: error_reporting:: nice_region_error:: find_anon_type:: find_anon_type;
55
55
use crate :: infer:: ExpectedFound ;
56
+ use crate :: traits:: util:: elaborate;
56
57
use crate :: traits:: {
57
58
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
58
59
PredicateObligation ,
59
60
} ;
60
61
61
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
62
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
62
63
use rustc_errors:: {
63
64
codes:: * , pluralize, struct_span_code_err, Applicability , Diag , DiagCtxt , DiagStyledString ,
64
65
ErrorGuaranteed , IntoDiagnosticArg , MultiSpan ,
@@ -458,11 +459,32 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
458
459
// the error. If all of these fails, we fall back to a rather
459
460
// general bit of code that displays the error information
460
461
RegionResolutionError :: ConcreteFailure ( origin, sub, sup) => {
462
+ let extra_info = self . find_trait_object_relate_failure_reason (
463
+ generic_param_scope,
464
+ & origin,
465
+ sub,
466
+ sup,
467
+ ) ;
461
468
let mut err = if sub. is_placeholder ( ) || sup. is_placeholder ( ) {
462
469
self . report_placeholder_failure ( origin, sub, sup)
463
470
} else {
464
471
self . report_concrete_failure ( origin, sub, sup)
465
472
} ;
473
+ if let Some ( ( primary_spans, relevant_bindings) ) = extra_info {
474
+ if primary_spans. has_primary_spans ( ) {
475
+ // We shorten the span from the whole field type to only the traits
476
+ // and lifetime bound that failed.
477
+ err. span ( primary_spans) ;
478
+ }
479
+ if relevant_bindings. has_primary_spans ( ) {
480
+ // Point at all the trait obligations for the lifetime that
481
+ // couldn't be met.
482
+ err. span_note (
483
+ relevant_bindings,
484
+ format ! ( "unmet `{sub}` obligations introduced here" ) ,
485
+ ) ;
486
+ }
487
+ }
466
488
if let hir:: def:: DefKind :: Impl { .. } =
467
489
self . tcx . def_kind ( generic_param_scope)
468
490
&& let Some ( def_id) =
@@ -471,28 +493,36 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
471
493
// Collect all the `Span`s corresponding to the predicates introducing
472
494
// the `sub` lifetime that couldn't be met (sometimes `'static`) on
473
495
// both the `trait` and the `impl`.
474
- let spans: Vec < Span > = self
475
- . tcx
476
- . predicates_of ( def_id)
477
- . predicates
478
- . iter ( )
479
- . chain (
480
- self . tcx . predicates_of ( generic_param_scope) . predicates . iter ( ) ,
481
- )
482
- . filter_map ( |( pred, span) | {
483
- if let Some ( ty:: ClauseKind :: TypeOutlives (
484
- ty:: OutlivesPredicate ( pred_ty, r) ,
485
- ) ) = pred. kind ( ) . no_bound_vars ( )
486
- && r == sub
487
- && let ty:: Param ( param) = pred_ty. kind ( )
488
- && param. name == kw:: SelfUpper
489
- {
490
- Some ( * span)
491
- } else {
492
- None
493
- }
494
- } )
495
- . collect ( ) ;
496
+ let spans: Vec < Span > = elaborate (
497
+ self . tcx ,
498
+ self . tcx
499
+ . predicates_of ( def_id)
500
+ . predicates
501
+ . iter ( )
502
+ . map ( |( p, sp) | ( p. as_predicate ( ) , * sp) ) ,
503
+ )
504
+ . chain ( elaborate (
505
+ self . tcx ,
506
+ self . tcx
507
+ . predicates_of ( generic_param_scope)
508
+ . predicates
509
+ . iter ( )
510
+ . map ( |( p, sp) | ( p. as_predicate ( ) , * sp) ) ,
511
+ ) )
512
+ . filter_map ( |( pred, pred_span) | {
513
+ if let ty:: PredicateKind :: Clause ( clause) = pred. kind ( ) . skip_binder ( )
514
+ && let ty:: ClauseKind :: TypeOutlives ( ty:: OutlivesPredicate (
515
+ _pred_ty,
516
+ r,
517
+ ) ) = clause
518
+ && r. kind ( ) == ty:: ReStatic
519
+ {
520
+ Some ( pred_span)
521
+ } else {
522
+ None
523
+ }
524
+ } )
525
+ . collect ( ) ;
496
526
497
527
if !spans. is_empty ( ) {
498
528
let spans_len = spans. len ( ) ;
@@ -2666,6 +2696,102 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2666
2696
if sub_region. is_error ( ) | sup_region. is_error ( ) { err. delay_as_bug ( ) } else { err. emit ( ) }
2667
2697
}
2668
2698
2699
+ /// If a field on a struct has a trait object with lifetime requirement that can't be satisfied
2700
+ /// by one of the traits in the trait object, shorten the span from the whole field type to only
2701
+ /// the relevant traits and the lifetime. We also collect the spans for the places where the
2702
+ /// traits' obligations were introduced.
2703
+ fn find_trait_object_relate_failure_reason (
2704
+ & self ,
2705
+ generic_param_scope : LocalDefId ,
2706
+ origin : & SubregionOrigin < ' tcx > ,
2707
+ sub : ty:: Region < ' tcx > ,
2708
+ sup : ty:: Region < ' tcx > ,
2709
+ ) -> Option < ( MultiSpan , MultiSpan ) > {
2710
+ let infer:: RelateRegionParamBound ( span) = origin else {
2711
+ return None ;
2712
+ } ;
2713
+ let Some ( hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Struct ( item, _) , .. } ) ) =
2714
+ self . tcx . hir ( ) . get_if_local ( generic_param_scope. into ( ) )
2715
+ else {
2716
+ return None ;
2717
+ } ;
2718
+ /// Collect all `hir::Ty<'_>` `Span`s for trait objects with the sup lifetime.
2719
+ pub struct HirTraitObjectVisitor < ' tcx > (
2720
+ pub Vec < & ' tcx hir:: PolyTraitRef < ' tcx > > ,
2721
+ pub ty:: Region < ' tcx > ,
2722
+ pub FxHashSet < Span > ,
2723
+ ) ;
2724
+ impl < ' tcx > Visitor < ' tcx > for HirTraitObjectVisitor < ' tcx > {
2725
+ fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' tcx > ) {
2726
+ // Find all the trait objects that have the lifetime that was found.
2727
+ if let hir:: TyKind :: TraitObject ( poly_trait_refs, lt, _) = t. kind
2728
+ && match ( lt. res , self . 1 . kind ( ) ) {
2729
+ (
2730
+ hir:: LifetimeName :: ImplicitObjectLifetimeDefault
2731
+ | hir:: LifetimeName :: Static ,
2732
+ ty:: RegionKind :: ReStatic ,
2733
+ ) => true ,
2734
+ ( hir:: LifetimeName :: Param ( a) , ty:: RegionKind :: ReEarlyParam ( b) ) => {
2735
+ a. to_def_id ( ) == b. def_id
2736
+ }
2737
+ _ => false ,
2738
+ }
2739
+ {
2740
+ for ptr in poly_trait_refs {
2741
+ // We'll filter the traits later, after collection.
2742
+ self . 0 . push ( ptr) ;
2743
+ }
2744
+ // We want to keep a span to the lifetime bound on the trait object.
2745
+ self . 2 . insert ( lt. ident . span ) ;
2746
+ }
2747
+ hir:: intravisit:: walk_ty ( self , t) ;
2748
+ }
2749
+ }
2750
+ let mut visitor = HirTraitObjectVisitor ( vec ! [ ] , sup, Default :: default ( ) ) ;
2751
+ for field in item. fields ( ) {
2752
+ if field. ty . span == * span {
2753
+ // `span` points at the type of a field, we only want to look for trait objects in
2754
+ // the field that failed.
2755
+ visitor. visit_ty ( field. ty ) ;
2756
+ }
2757
+ }
2758
+
2759
+ // The display of these spans will not change regardless or sorting.
2760
+ #[ allow( rustc:: potential_query_instability) ]
2761
+ let mut primary_spans: Vec < Span > = visitor. 2 . into_iter ( ) . collect ( ) ;
2762
+ let mut relevant_bindings: Vec < Span > = vec ! [ ] ;
2763
+ for ptr in visitor. 0 {
2764
+ if let Some ( def_id) = ptr. trait_ref . trait_def_id ( ) {
2765
+ // Find the bounds on the trait with the lifetime that couldn't be met.
2766
+ let bindings: Vec < Span > = elaborate (
2767
+ self . tcx ,
2768
+ self . tcx
2769
+ . predicates_of ( def_id)
2770
+ . predicates
2771
+ . iter ( )
2772
+ . map ( |( p, sp) | ( p. as_predicate ( ) , * sp) ) ,
2773
+ )
2774
+ . filter_map ( |( pred, pred_span) | {
2775
+ if let ty:: PredicateKind :: Clause ( clause) = pred. kind ( ) . skip_binder ( )
2776
+ && let ty:: ClauseKind :: TypeOutlives ( ty:: OutlivesPredicate ( _pred_ty, r) ) =
2777
+ clause
2778
+ && r == sub
2779
+ {
2780
+ Some ( pred_span)
2781
+ } else {
2782
+ None
2783
+ }
2784
+ } )
2785
+ . collect ( ) ;
2786
+ if !bindings. is_empty ( ) {
2787
+ primary_spans. push ( ptr. span ) ;
2788
+ relevant_bindings. extend ( bindings) ;
2789
+ }
2790
+ }
2791
+ }
2792
+ Some ( ( primary_spans. into ( ) , relevant_bindings. into ( ) ) )
2793
+ }
2794
+
2669
2795
/// Determine whether an error associated with the given span and definition
2670
2796
/// should be treated as being caused by the implicit `From` conversion
2671
2797
/// within `?` desugaring.
0 commit comments