@@ -16,14 +16,12 @@ use rustc_infer::infer::{
1616 HirTraitObjectVisitor , NiceRegionError , TraitObjectVisitor ,
1717 } ,
1818 error_reporting:: unexpected_hidden_region_diagnostic,
19- NllRegionVariableOrigin , RelateParamBound ,
19+ BoundRegionConversionTime , NllRegionVariableOrigin , RelateParamBound ,
2020} ;
2121use rustc_middle:: hir:: place:: PlaceBase ;
2222use rustc_middle:: mir:: { ConstraintCategory , ReturnConstraint } ;
23- use rustc_middle:: ty:: GenericArgs ;
24- use rustc_middle:: ty:: TypeVisitor ;
25- use rustc_middle:: ty:: { self , RegionVid , Ty } ;
26- use rustc_middle:: ty:: { Region , TyCtxt } ;
23+ use rustc_middle:: traits:: ObligationCauseCode ;
24+ use rustc_middle:: ty:: { self , GenericArgs , Region , RegionVid , Ty , TyCtxt , TypeVisitor } ;
2725use rustc_span:: symbol:: { kw, Ident } ;
2826use rustc_span:: Span ;
2927
@@ -490,19 +488,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
490488 }
491489 } ;
492490
491+ self . explain_impl_static_obligation ( & mut diag, cause. code ( ) , outlived_fr) ;
492+
493493 match variance_info {
494494 ty:: VarianceDiagInfo :: None => { }
495495 ty:: VarianceDiagInfo :: Invariant { ty, param_index } => {
496496 let ( desc, note) = match ty. kind ( ) {
497497 ty:: RawPtr ( ty_mut) => {
498- assert_eq ! ( ty_mut. mutbl, rustc_hir :: Mutability :: Mut ) ;
498+ assert_eq ! ( ty_mut. mutbl, hir :: Mutability :: Mut ) ;
499499 (
500500 format ! ( "a mutable pointer to `{}`" , ty_mut. ty) ,
501501 "mutable pointers are invariant over their type parameter" . to_string ( ) ,
502502 )
503503 }
504504 ty:: Ref ( _, inner_ty, mutbl) => {
505- assert_eq ! ( * mutbl, rustc_hir :: Mutability :: Mut ) ;
505+ assert_eq ! ( * mutbl, hir :: Mutability :: Mut ) ;
506506 (
507507 format ! ( "a mutable reference to `{inner_ty}`" ) ,
508508 "mutable references are invariant over their type parameter"
@@ -518,10 +518,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
518518 let adt_desc = adt. descr ( ) ;
519519
520520 let desc = format ! (
521- "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant"
521+ "the type `{ty}`, which makes the generic argument `{generic_arg}` \
522+ invariant"
522523 ) ;
523524 let note = format ! (
524- "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`"
525+ "the {adt_desc} `{base_ty}` is invariant over the parameter \
526+ `{base_generic_arg}`"
525527 ) ;
526528 ( desc, note)
527529 }
@@ -539,21 +541,224 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
539541 } ;
540542 diag. note ( format ! ( "requirement occurs because of {desc}" , ) ) ;
541543 diag. note ( note) ;
542- diag. help ( "see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance" ) ;
544+ diag. help (
545+ "see <https://doc.rust-lang.org/nomicon/subtyping.html> for more \
546+ information about variance",
547+ ) ;
543548 }
544549 }
545550
546551 for extra in extra_info {
547552 match extra {
548553 ExtraConstraintInfo :: PlaceholderFromPredicate ( span) => {
549- diag. span_note ( span, "due to current limitations in the borrow checker, this implies a `'static` lifetime" ) ;
554+ diag. span_note (
555+ span,
556+ "due to current limitations in the borrow checker, this implies a \
557+ `'static` lifetime",
558+ ) ;
550559 }
551560 }
552561 }
553562
554563 self . buffer_error ( diag) ;
555564 }
556565
566+ /// Report a specialized error when a `'static` obligation comes from an `impl dyn Trait`
567+ ///
568+ /// ```text
569+ /// error: lifetime may not live long enough
570+ /// --> $DIR/static-impl-obligation.rs:8:27
571+ /// |
572+ /// LL | fn bar<'a>(x: &'a &'a u32) {
573+ /// | -- lifetime `'a` defined here
574+ /// LL | let y: &dyn Foo = x;
575+ /// | ^ cast requires that `'a` must outlive `'static`
576+ /// LL | y.hello();
577+ /// | --------- calling this method introduces a `'static` lifetime requirement
578+ /// |
579+ /// note: the `impl` on `(dyn a::Foo + 'static)` has a `'static` lifetime requirement
580+ /// --> $DIR/static-impl-obligation.rs:4:10
581+ /// |
582+ /// LL | impl dyn Foo {
583+ /// | ^^^^^^^
584+ /// help: relax the implicit `'static` bound on the impl
585+ /// |
586+ /// LL | impl dyn Foo + '_ {
587+ /// | ++++
588+ /// ```
589+ /// ```text
590+ /// error: lifetime may not live long enough
591+ /// --> $DIR/static-impl-obligation.rs:173:27
592+ /// |
593+ /// LL | fn bar<'a>(x: &'a &'a u32) {
594+ /// | -- lifetime `'a` defined here
595+ /// LL | let y: &dyn Foo = x;
596+ /// | ^ cast requires that `'a` must outlive `'static`
597+ /// LL | y.hello();
598+ /// | --------- calling this method introduces a `'static` lifetime requirement
599+ /// |
600+ /// note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements
601+ /// --> $DIR/static-impl-obligation.rs:169:20
602+ /// |
603+ /// LL | impl dyn Foo + 'static where Self: 'static {
604+ /// | ^^^^^^^ ^^^^^^^
605+ /// LL | fn hello(&self) where Self: 'static {}
606+ /// | ^^^^^^^
607+ /// ```
608+ fn explain_impl_static_obligation (
609+ & self ,
610+ diag : & mut DiagnosticBuilder < ' _ > ,
611+ code : & ObligationCauseCode < ' tcx > ,
612+ outlived_fr : RegionVid ,
613+ ) {
614+ let tcx = self . infcx . tcx ;
615+ let ObligationCauseCode :: MethodCallConstraint ( ty, call_span) = code else {
616+ return ;
617+ } ;
618+ let ty:: FnDef ( def_id, args) = ty. kind ( ) else {
619+ return ;
620+ } ;
621+ let parent = tcx. parent ( * def_id) ;
622+ let hir:: def:: DefKind :: Impl { .. } = tcx. def_kind ( parent) else {
623+ return ;
624+ } ;
625+ let ty = tcx. type_of ( parent) . instantiate ( tcx, args) ;
626+ let ty:: Dynamic ( _, region, ty:: Dyn ) = ty. kind ( ) else {
627+ return ;
628+ } ;
629+ if ![ ty:: ReStatic , ty:: ReErased ] . contains ( & region. kind ( ) ) {
630+ return ;
631+ } ;
632+ if self . to_error_region ( outlived_fr) != Some ( tcx. lifetimes . re_static ) {
633+ return ;
634+ }
635+ // FIXME: there's a case that's yet to be handled: `impl dyn Trait + '_ where Self: '_`
636+ // causes *two* errors to be produded, one about `where Self: '_` not being allowed,
637+ // and the regular error with no additional information about "lifetime may not live
638+ // long enough for `'static`" without mentioning where it came from. This is because
639+ // our error recovery fallback is indeed `ReStatic`. We should at some point introduce
640+ // a `ReError` instead to avoid this and other similar issues.
641+
642+ // Look for `'static` bounds in the generics of the method and the `impl`.
643+ // ```
644+ // impl dyn Trait where Self: 'static {
645+ // fn foo(&self) where Self: 'static {}
646+ // }
647+ // ```
648+ let mut predicates: Vec < Span > = tcx
649+ . predicates_of ( * def_id)
650+ . predicates
651+ . iter ( )
652+ . chain ( tcx. predicates_of ( parent) . predicates . iter ( ) )
653+ . filter_map ( |( pred, pred_span) | {
654+ if let Some ( ty:: ClauseKind :: TypeOutlives ( ty:: OutlivesPredicate ( pred_ty, r) ) ) =
655+ pred. kind ( ) . no_bound_vars ( )
656+ // Look for `'static` bounds
657+ && r. kind ( ) == ty:: ReStatic
658+ // We only want bounds on `Self`
659+ && self . infcx . can_eq ( self . param_env , ty, pred_ty)
660+ {
661+ Some ( * pred_span)
662+ } else {
663+ None
664+ }
665+ } )
666+ . collect ( ) ;
667+
668+ // Look at the receiver for `&'static self`, which introduces a `'static` obligation.
669+ // ```
670+ // impl dyn Trait {
671+ // fn foo(&'static self) {}
672+ // }
673+ // ```
674+ if let ty:: Ref ( region, _, _) = self
675+ . infcx
676+ . instantiate_binder_with_fresh_vars (
677+ * call_span,
678+ BoundRegionConversionTime :: FnCall ,
679+ tcx. fn_sig ( * def_id) . instantiate_identity ( ) . inputs ( ) . map_bound ( |inputs| inputs[ 0 ] ) ,
680+ )
681+ . kind ( )
682+ && * region == tcx. lifetimes . re_static
683+ && let Some ( assoc) = tcx. opt_associated_item ( * def_id)
684+ && assoc. fn_has_self_parameter
685+ {
686+ // We have a `&'static self` receiver.
687+ if let Some ( def_id) = def_id. as_local ( )
688+ && let owner = tcx. expect_hir_owner_node ( def_id)
689+ && let Some ( decl) = owner. fn_decl ( )
690+ && let Some ( ty) = decl. inputs . get ( 0 )
691+ {
692+ // Point at the `&'static self` receiver.
693+ predicates. push ( ty. span ) ;
694+ } else {
695+ // The method is not defined on the local crate, point at the signature
696+ // instead of just the receiver as an approximation.
697+ predicates. push ( tcx. def_span ( * def_id) )
698+ }
699+ }
700+
701+ // When we have the HIR `Node` at hand, see if we can identify an
702+ // implicit `'static` bound in an `impl dyn Trait {}` and if that's
703+ // the only restriction, suggest relaxing it.
704+ if let Some ( hir:: Node :: Item ( hir:: Item {
705+ kind :
706+ hir:: ItemKind :: Impl ( hir:: Impl {
707+ self_ty : hir:: Ty { kind : hir:: TyKind :: TraitObject ( _, lt, _) , span, .. } ,
708+ ..
709+ } ) ,
710+ ..
711+ } ) ) = tcx. hir ( ) . get_if_local ( parent)
712+ && let Some ( hir:: Node :: ImplItem ( hir:: ImplItem { .. } ) ) = tcx. hir ( ) . get_if_local ( * def_id)
713+ {
714+ let suggestion = match lt. res {
715+ hir:: LifetimeName :: ImplicitObjectLifetimeDefault if predicates. is_empty ( ) => {
716+ // ```
717+ // impl dyn Trait {}
718+ // ```
719+ Some ( (
720+ span. shrink_to_hi ( ) ,
721+ "consider relaxing the implicit `'static` requirement on the impl" ,
722+ " + '_" ,
723+ ) )
724+ }
725+ hir:: LifetimeName :: Static if predicates. is_empty ( ) => {
726+ // ```
727+ // impl dyn Trait + 'static {}
728+ // ```
729+ Some ( ( lt. ident . span , "consider replacing this `'static` requirement" , "'_" ) )
730+ }
731+ _ => None ,
732+ } ;
733+ if let Some ( ( span, msg, sugg) ) = suggestion {
734+ diag. span_suggestion_verbose ( span, msg, sugg, Applicability :: MachineApplicable ) ;
735+ }
736+ if let hir:: LifetimeName :: ImplicitObjectLifetimeDefault | hir:: LifetimeName :: Static =
737+ lt. res
738+ {
739+ predicates. push ( lt. ident . span ) ;
740+ }
741+ } else if * region == tcx. lifetimes . re_static {
742+ // The `self_ty` has a `'static` bound, either implicit or explicit, but we don't
743+ // have access to the HIR to identify which one nor to provide a targetted enough
744+ // `Span`, so instead we fall back to pointing at the `impl` header instead.
745+ predicates. push ( tcx. def_span ( parent) ) ;
746+ }
747+ if !predicates. is_empty ( ) {
748+ diag. span_label (
749+ * call_span,
750+ "calling this method introduces a `'static` lifetime requirement" ,
751+ ) ;
752+ let a_static_lt = if predicates. len ( ) == 1 {
753+ "a `'static` lifetime requirement"
754+ } else {
755+ "`'static` lifetime requirements"
756+ } ;
757+ let span: MultiSpan = predicates. into ( ) ;
758+ diag. span_note ( span, format ! ( "the `impl` on `{ty}` has {a_static_lt}" ) ) ;
759+ }
760+ }
761+
557762 /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
558763 /// This function expects `fr` to be local and `outlived_fr` to not be local.
559764 ///
@@ -793,7 +998,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
793998 self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
794999 self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
7951000 self . suggest_move_on_borrowing_closure ( & mut diag) ;
796-
7971001 diag
7981002 }
7991003
@@ -980,12 +1184,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
9801184 "calling this method introduces the `impl`'s `'static` requirement" ,
9811185 ) ;
9821186 err. subdiagnostic ( RequireStaticErr :: UsedImpl { multi_span } ) ;
983- err. span_suggestion_verbose (
984- span. shrink_to_hi ( ) ,
985- "consider relaxing the implicit `'static` requirement" ,
986- " + '_" ,
987- Applicability :: MaybeIncorrect ,
988- ) ;
1187+ // We already handle the `self_ty` specifically in `explain_impl_static_obligation`.
1188+ if * span != self_ty. span {
1189+ err. span_suggestion_verbose (
1190+ span. shrink_to_hi ( ) ,
1191+ "consider relaxing the implicit `'static` requirement" ,
1192+ " + '_" ,
1193+ Applicability :: MaybeIncorrect ,
1194+ ) ;
1195+ }
9891196 suggested = true ;
9901197 }
9911198 }
0 commit comments