@@ -53,12 +53,13 @@ use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
5353use crate :: infer;
5454use crate :: infer:: error_reporting:: nice_region_error:: find_anon_type:: find_anon_type;
5555use crate :: infer:: ExpectedFound ;
56+ use crate :: traits:: util:: elaborate;
5657use crate :: traits:: {
5758 IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
5859 PredicateObligation ,
5960} ;
6061
61- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
62+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
6263use rustc_errors:: {
6364 codes:: * , pluralize, struct_span_code_err, Applicability , Diag , DiagCtxt , DiagStyledString ,
6465 ErrorGuaranteed , IntoDiagArg , MultiSpan ,
@@ -458,11 +459,32 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
458459 // the error. If all of these fails, we fall back to a rather
459460 // general bit of code that displays the error information
460461 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+ ) ;
461468 let mut err = if sub. is_placeholder ( ) || sup. is_placeholder ( ) {
462469 self . report_placeholder_failure ( origin, sub, sup)
463470 } else {
464471 self . report_concrete_failure ( origin, sub, sup)
465472 } ;
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+ }
466488 if let hir:: def:: DefKind :: Impl { .. } =
467489 self . tcx . def_kind ( generic_param_scope)
468490 && let Some ( def_id) =
@@ -471,28 +493,36 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
471493 // Collect all the `Span`s corresponding to the predicates introducing
472494 // the `sub` lifetime that couldn't be met (sometimes `'static`) on
473495 // 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 ( ) ;
496526
497527 if !spans. is_empty ( ) {
498528 let spans_len = spans. len ( ) ;
@@ -2677,6 +2707,102 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
26772707 if sub_region. is_error ( ) | sup_region. is_error ( ) { err. delay_as_bug ( ) } else { err. emit ( ) }
26782708 }
26792709
2710+ /// If a field on a struct has a trait object with lifetime requirement that can't be satisfied
2711+ /// by one of the traits in the trait object, shorten the span from the whole field type to only
2712+ /// the relevant traits and the lifetime. We also collect the spans for the places where the
2713+ /// traits' obligations were introduced.
2714+ fn find_trait_object_relate_failure_reason (
2715+ & self ,
2716+ generic_param_scope : LocalDefId ,
2717+ origin : & SubregionOrigin < ' tcx > ,
2718+ sub : ty:: Region < ' tcx > ,
2719+ sup : ty:: Region < ' tcx > ,
2720+ ) -> Option < ( MultiSpan , MultiSpan ) > {
2721+ let infer:: RelateRegionParamBound ( span) = origin else {
2722+ return None ;
2723+ } ;
2724+ let Some ( hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Struct ( item, _) , .. } ) ) =
2725+ self . tcx . hir ( ) . get_if_local ( generic_param_scope. into ( ) )
2726+ else {
2727+ return None ;
2728+ } ;
2729+ /// Collect all `hir::Ty<'_>` `Span`s for trait objects with the sup lifetime.
2730+ pub struct HirTraitObjectVisitor < ' tcx > (
2731+ pub Vec < & ' tcx hir:: PolyTraitRef < ' tcx > > ,
2732+ pub ty:: Region < ' tcx > ,
2733+ pub FxHashSet < Span > ,
2734+ ) ;
2735+ impl < ' tcx > Visitor < ' tcx > for HirTraitObjectVisitor < ' tcx > {
2736+ fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' tcx > ) {
2737+ // Find all the trait objects that have the lifetime that was found.
2738+ if let hir:: TyKind :: TraitObject ( poly_trait_refs, lt, _) = t. kind
2739+ && match ( lt. res , self . 1 . kind ( ) ) {
2740+ (
2741+ hir:: LifetimeName :: ImplicitObjectLifetimeDefault
2742+ | hir:: LifetimeName :: Static ,
2743+ ty:: RegionKind :: ReStatic ,
2744+ ) => true ,
2745+ ( hir:: LifetimeName :: Param ( a) , ty:: RegionKind :: ReEarlyParam ( b) ) => {
2746+ a. to_def_id ( ) == b. def_id
2747+ }
2748+ _ => false ,
2749+ }
2750+ {
2751+ for ptr in poly_trait_refs {
2752+ // We'll filter the traits later, after collection.
2753+ self . 0 . push ( ptr) ;
2754+ }
2755+ // We want to keep a span to the lifetime bound on the trait object.
2756+ self . 2 . insert ( lt. ident . span ) ;
2757+ }
2758+ hir:: intravisit:: walk_ty ( self , t) ;
2759+ }
2760+ }
2761+ let mut visitor = HirTraitObjectVisitor ( vec ! [ ] , sup, Default :: default ( ) ) ;
2762+ for field in item. fields ( ) {
2763+ if field. ty . span == * span {
2764+ // `span` points at the type of a field, we only want to look for trait objects in
2765+ // the field that failed.
2766+ visitor. visit_ty ( field. ty ) ;
2767+ }
2768+ }
2769+
2770+ // The display of these spans will not change regardless or sorting.
2771+ #[ allow( rustc:: potential_query_instability) ]
2772+ let mut primary_spans: Vec < Span > = visitor. 2 . into_iter ( ) . collect ( ) ;
2773+ let mut relevant_bindings: Vec < Span > = vec ! [ ] ;
2774+ for ptr in visitor. 0 {
2775+ if let Some ( def_id) = ptr. trait_ref . trait_def_id ( ) {
2776+ // Find the bounds on the trait with the lifetime that couldn't be met.
2777+ let bindings: Vec < Span > = elaborate (
2778+ self . tcx ,
2779+ self . tcx
2780+ . predicates_of ( def_id)
2781+ . predicates
2782+ . iter ( )
2783+ . map ( |( p, sp) | ( p. as_predicate ( ) , * sp) ) ,
2784+ )
2785+ . filter_map ( |( pred, pred_span) | {
2786+ if let ty:: PredicateKind :: Clause ( clause) = pred. kind ( ) . skip_binder ( )
2787+ && let ty:: ClauseKind :: TypeOutlives ( ty:: OutlivesPredicate ( _pred_ty, r) ) =
2788+ clause
2789+ && r == sub
2790+ {
2791+ Some ( pred_span)
2792+ } else {
2793+ None
2794+ }
2795+ } )
2796+ . collect ( ) ;
2797+ if !bindings. is_empty ( ) {
2798+ primary_spans. push ( ptr. span ) ;
2799+ relevant_bindings. extend ( bindings) ;
2800+ }
2801+ }
2802+ }
2803+ Some ( ( primary_spans. into ( ) , relevant_bindings. into ( ) ) )
2804+ }
2805+
26802806 /// Determine whether an error associated with the given span and definition
26812807 /// should be treated as being caused by the implicit `From` conversion
26822808 /// within `?` desugaring.
0 commit comments