@@ -16,14 +16,12 @@ use rustc_infer::infer::{
16
16
HirTraitObjectVisitor , NiceRegionError , TraitObjectVisitor ,
17
17
} ,
18
18
error_reporting:: unexpected_hidden_region_diagnostic,
19
- NllRegionVariableOrigin , RelateParamBound ,
19
+ BoundRegionConversionTime , NllRegionVariableOrigin , RelateParamBound ,
20
20
} ;
21
21
use rustc_middle:: hir:: place:: PlaceBase ;
22
22
use 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 } ;
27
25
use rustc_span:: symbol:: { kw, Ident } ;
28
26
use rustc_span:: Span ;
29
27
@@ -490,19 +488,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
490
488
}
491
489
} ;
492
490
491
+ self . explain_impl_static_obligation ( & mut diag, cause. code ( ) , outlived_fr) ;
492
+
493
493
match variance_info {
494
494
ty:: VarianceDiagInfo :: None => { }
495
495
ty:: VarianceDiagInfo :: Invariant { ty, param_index } => {
496
496
let ( desc, note) = match ty. kind ( ) {
497
497
ty:: RawPtr ( ty_mut) => {
498
- assert_eq ! ( ty_mut. mutbl, rustc_hir :: Mutability :: Mut ) ;
498
+ assert_eq ! ( ty_mut. mutbl, hir :: Mutability :: Mut ) ;
499
499
(
500
500
format ! ( "a mutable pointer to `{}`" , ty_mut. ty) ,
501
501
"mutable pointers are invariant over their type parameter" . to_string ( ) ,
502
502
)
503
503
}
504
504
ty:: Ref ( _, inner_ty, mutbl) => {
505
- assert_eq ! ( * mutbl, rustc_hir :: Mutability :: Mut ) ;
505
+ assert_eq ! ( * mutbl, hir :: Mutability :: Mut ) ;
506
506
(
507
507
format ! ( "a mutable reference to `{inner_ty}`" ) ,
508
508
"mutable references are invariant over their type parameter"
@@ -518,10 +518,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
518
518
let adt_desc = adt. descr ( ) ;
519
519
520
520
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"
522
523
) ;
523
524
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}`"
525
527
) ;
526
528
( desc, note)
527
529
}
@@ -539,21 +541,224 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
539
541
} ;
540
542
diag. note ( format ! ( "requirement occurs because of {desc}" , ) ) ;
541
543
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
+ ) ;
543
548
}
544
549
}
545
550
546
551
for extra in extra_info {
547
552
match extra {
548
553
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
+ ) ;
550
559
}
551
560
}
552
561
}
553
562
554
563
self . buffer_error ( diag) ;
555
564
}
556
565
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
+
557
762
/// Report a specialized error when `FnMut` closures return a reference to a captured variable.
558
763
/// This function expects `fr` to be local and `outlived_fr` to not be local.
559
764
///
@@ -793,7 +998,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
793
998
self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
794
999
self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
795
1000
self . suggest_move_on_borrowing_closure ( & mut diag) ;
796
-
797
1001
diag
798
1002
}
799
1003
@@ -980,12 +1184,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
980
1184
"calling this method introduces the `impl`'s `'static` requirement" ,
981
1185
) ;
982
1186
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
+ }
989
1196
suggested = true ;
990
1197
}
991
1198
}
0 commit comments