@@ -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 , IntoDiagnosticArg , 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 ( ) ;
@@ -2666,6 +2696,102 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
26662696 if sub_region. is_error ( ) | sup_region. is_error ( ) { err. delay_as_bug ( ) } else { err. emit ( ) }
26672697 }
26682698
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+
26692795 /// Determine whether an error associated with the given span and definition
26702796 /// should be treated as being caused by the implicit `From` conversion
26712797 /// within `?` desugaring.
0 commit comments