1
1
//! Error reporting machinery for lifetime errors.
2
2
3
+ use rustc_ast:: TraitObjectSyntax :: Dyn ;
3
4
use rustc_data_structures:: fx:: FxIndexSet ;
4
5
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , MultiSpan } ;
5
6
use rustc_hir as hir;
@@ -16,14 +17,12 @@ use rustc_infer::infer::{
16
17
HirTraitObjectVisitor , NiceRegionError , TraitObjectVisitor ,
17
18
} ,
18
19
error_reporting:: unexpected_hidden_region_diagnostic,
19
- NllRegionVariableOrigin , RelateParamBound ,
20
+ BoundRegionConversionTime , NllRegionVariableOrigin , RelateParamBound ,
20
21
} ;
21
22
use rustc_middle:: hir:: place:: PlaceBase ;
22
23
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 } ;
24
+ use rustc_middle:: traits:: ObligationCauseCode ;
25
+ use rustc_middle:: ty:: { self , GenericArgs , Region , RegionVid , Ty , TyCtxt , TypeVisitor } ;
27
26
use rustc_span:: symbol:: { kw, Ident } ;
28
27
use rustc_span:: Span ;
29
28
@@ -490,19 +489,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
490
489
}
491
490
} ;
492
491
492
+ self . explain_impl_static_obligation ( & mut diag, cause. code ( ) , outlived_fr) ;
493
+
493
494
match variance_info {
494
495
ty:: VarianceDiagInfo :: None => { }
495
496
ty:: VarianceDiagInfo :: Invariant { ty, param_index } => {
496
497
let ( desc, note) = match ty. kind ( ) {
497
498
ty:: RawPtr ( ty_mut) => {
498
- assert_eq ! ( ty_mut. mutbl, rustc_hir :: Mutability :: Mut ) ;
499
+ assert_eq ! ( ty_mut. mutbl, hir :: Mutability :: Mut ) ;
499
500
(
500
501
format ! ( "a mutable pointer to `{}`" , ty_mut. ty) ,
501
502
"mutable pointers are invariant over their type parameter" . to_string ( ) ,
502
503
)
503
504
}
504
505
ty:: Ref ( _, inner_ty, mutbl) => {
505
- assert_eq ! ( * mutbl, rustc_hir :: Mutability :: Mut ) ;
506
+ assert_eq ! ( * mutbl, hir :: Mutability :: Mut ) ;
506
507
(
507
508
format ! ( "a mutable reference to `{inner_ty}`" ) ,
508
509
"mutable references are invariant over their type parameter"
@@ -518,10 +519,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
518
519
let adt_desc = adt. descr ( ) ;
519
520
520
521
let desc = format ! (
521
- "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant"
522
+ "the type `{ty}`, which makes the generic argument `{generic_arg}` \
523
+ invariant"
522
524
) ;
523
525
let note = format ! (
524
- "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`"
526
+ "the {adt_desc} `{base_ty}` is invariant over the parameter \
527
+ `{base_generic_arg}`"
525
528
) ;
526
529
( desc, note)
527
530
}
@@ -539,21 +542,225 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
539
542
} ;
540
543
diag. note ( format ! ( "requirement occurs because of {desc}" , ) ) ;
541
544
diag. note ( note) ;
542
- diag. help ( "see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance" ) ;
545
+ diag. help (
546
+ "see <https://doc.rust-lang.org/nomicon/subtyping.html> for more \
547
+ information about variance",
548
+ ) ;
543
549
}
544
550
}
545
551
546
552
for extra in extra_info {
547
553
match extra {
548
554
ExtraConstraintInfo :: PlaceholderFromPredicate ( span) => {
549
- diag. span_note ( span, "due to current limitations in the borrow checker, this implies a `'static` lifetime" ) ;
555
+ diag. span_note (
556
+ span,
557
+ "due to current limitations in the borrow checker, this implies a \
558
+ `'static` lifetime",
559
+ ) ;
550
560
}
551
561
}
552
562
}
553
563
554
564
self . buffer_error ( diag) ;
555
565
}
556
566
567
+ /// Report a specialized error when a `'static` obligation comes from an `impl dyn Trait`
568
+ ///
569
+ /// ```text
570
+ /// error: lifetime may not live long enough
571
+ /// --> $DIR/static-impl-obligation.rs:8:27
572
+ /// |
573
+ /// LL | fn bar<'a>(x: &'a &'a u32) {
574
+ /// | -- lifetime `'a` defined here
575
+ /// LL | let y: &dyn Foo = x;
576
+ /// | ^ cast requires that `'a` must outlive `'static`
577
+ /// LL | y.hello();
578
+ /// | --------- calling this method introduces a `'static` lifetime requirement
579
+ /// |
580
+ /// note: the `impl` on `(dyn a::Foo + 'static)` has a `'static` lifetime requirement
581
+ /// --> $DIR/static-impl-obligation.rs:4:10
582
+ /// |
583
+ /// LL | impl dyn Foo {
584
+ /// | ^^^^^^^
585
+ /// help: relax the implicit `'static` bound on the impl
586
+ /// |
587
+ /// LL | impl dyn Foo + '_ {
588
+ /// | ++++
589
+ /// ```
590
+ /// ```text
591
+ /// error: lifetime may not live long enough
592
+ /// --> $DIR/static-impl-obligation.rs:173:27
593
+ /// |
594
+ /// LL | fn bar<'a>(x: &'a &'a u32) {
595
+ /// | -- lifetime `'a` defined here
596
+ /// LL | let y: &dyn Foo = x;
597
+ /// | ^ cast requires that `'a` must outlive `'static`
598
+ /// LL | y.hello();
599
+ /// | --------- calling this method introduces a `'static` lifetime requirement
600
+ /// |
601
+ /// note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements
602
+ /// --> $DIR/static-impl-obligation.rs:169:20
603
+ /// |
604
+ /// LL | impl dyn Foo + 'static where Self: 'static {
605
+ /// | ^^^^^^^ ^^^^^^^
606
+ /// LL | fn hello(&self) where Self: 'static {}
607
+ /// | ^^^^^^^
608
+ /// ```
609
+ fn explain_impl_static_obligation (
610
+ & self ,
611
+ diag : & mut DiagnosticBuilder < ' _ > ,
612
+ code : & ObligationCauseCode < ' tcx > ,
613
+ outlived_fr : RegionVid ,
614
+ ) {
615
+ let tcx = self . infcx . tcx ;
616
+ let ObligationCauseCode :: MethodCallConstraint ( ty, call_span) = code else {
617
+ return ;
618
+ } ;
619
+ let ty:: FnDef ( def_id, args) = ty. kind ( ) else {
620
+ return ;
621
+ } ;
622
+ let parent = tcx. parent ( * def_id) ;
623
+ let hir:: def:: DefKind :: Impl { .. } = tcx. def_kind ( parent) else {
624
+ return ;
625
+ } ;
626
+ let ty = tcx. type_of ( parent) . instantiate ( tcx, args) ;
627
+ if self . to_error_region ( outlived_fr) != Some ( tcx. lifetimes . re_static ) {
628
+ return ;
629
+ }
630
+ // FIXME: there's a case that's yet to be handled: `impl dyn Trait + '_ where Self: '_`
631
+ // causes *two* errors to be produded, one about `where Self: '_` not being allowed,
632
+ // and the regular error with no additional information about "lifetime may not live
633
+ // long enough for `'static`" without mentioning where it came from. This is because
634
+ // our error recovery fallback is indeed `ReStatic`. We should at some point introduce
635
+ // a `ReError` instead to avoid this and other similar issues.
636
+
637
+ // Look for `'static` bounds in the generics of the method and the `impl`.
638
+ // ```
639
+ // impl dyn Trait where Self: 'static {
640
+ // fn foo(&self) where Self: 'static {}
641
+ // }
642
+ // ```
643
+ let mut predicates: Vec < Span > = tcx
644
+ . predicates_of ( * def_id)
645
+ . predicates
646
+ . iter ( )
647
+ . chain ( tcx. predicates_of ( parent) . predicates . iter ( ) )
648
+ . filter_map ( |( pred, pred_span) | {
649
+ if let Some ( ty:: ClauseKind :: TypeOutlives ( ty:: OutlivesPredicate ( pred_ty, r) ) ) =
650
+ pred. kind ( ) . no_bound_vars ( )
651
+ // Look for `'static` bounds
652
+ && r. kind ( ) == ty:: ReStatic
653
+ // We only want bounds on `Self`
654
+ && self . infcx . can_eq ( self . param_env , ty, pred_ty)
655
+ {
656
+ Some ( * pred_span)
657
+ } else {
658
+ None
659
+ }
660
+ } )
661
+ . collect ( ) ;
662
+
663
+ // Look at the receiver for `&'static self`, which introduces a `'static` obligation.
664
+ // ```
665
+ // impl dyn Trait {
666
+ // fn foo(&'static self) {}
667
+ // }
668
+ // ```
669
+ if let ty:: Ref ( region, _, _) = self
670
+ . infcx
671
+ . instantiate_binder_with_fresh_vars (
672
+ * call_span,
673
+ BoundRegionConversionTime :: FnCall ,
674
+ tcx. fn_sig ( * def_id) . instantiate_identity ( ) . inputs ( ) . map_bound ( |inputs| inputs[ 0 ] ) ,
675
+ )
676
+ . kind ( )
677
+ && * region == tcx. lifetimes . re_static
678
+ && let Some ( assoc) = tcx. opt_associated_item ( * def_id)
679
+ && assoc. fn_has_self_parameter
680
+ {
681
+ // We have a `&'static self` receiver.
682
+ if let Some ( def_id) = def_id. as_local ( )
683
+ && let owner = tcx. expect_hir_owner_node ( def_id)
684
+ && let Some ( decl) = owner. fn_decl ( )
685
+ && let Some ( ty) = decl. inputs . get ( 0 )
686
+ {
687
+ // Point at the `&'static self` receiver.
688
+ predicates. push ( ty. span ) ;
689
+ } else {
690
+ // The method is not defined on the local crate, point at the signature
691
+ // instead of just the receiver as an approximation.
692
+ predicates. push ( tcx. def_span ( * def_id) )
693
+ }
694
+ }
695
+
696
+ // When we have the HIR `Node` at hand, see if we can identify an
697
+ // implicit `'static` bound in an `impl dyn Trait {}` and if that's
698
+ // the only restriction, suggest relaxing it.
699
+ if let Some ( hir:: Node :: Item ( hir:: Item {
700
+ kind :
701
+ hir:: ItemKind :: Impl ( hir:: Impl {
702
+ self_ty : hir:: Ty { kind : hir:: TyKind :: TraitObject ( _, lt, _) , span, .. } ,
703
+ ..
704
+ } ) ,
705
+ ..
706
+ } ) ) = tcx. hir ( ) . get_if_local ( parent)
707
+ && let Some ( hir:: Node :: ImplItem ( hir:: ImplItem { .. } ) ) = tcx. hir ( ) . get_if_local ( * def_id)
708
+ {
709
+ let suggestion = match lt. res {
710
+ hir:: LifetimeName :: ImplicitObjectLifetimeDefault if predicates. is_empty ( ) => {
711
+ // `impl dyn Trait {}`
712
+ Some ( (
713
+ span. shrink_to_hi ( ) ,
714
+ "consider relaxing the implicit `'static` requirement on the impl" ,
715
+ " + '_" ,
716
+ ) )
717
+ }
718
+ hir:: LifetimeName :: Static if predicates. is_empty ( ) => {
719
+ // `impl dyn Trait + 'static {}`
720
+ Some ( ( lt. ident . span , "consider replacing this `'static` requirement" , "'_" ) )
721
+ }
722
+ _ => None ,
723
+ } ;
724
+ if let Some ( ( span, msg, sugg) ) = suggestion {
725
+ // We only emit the suggestion to write `impl dyn Trait + '_ {}` if that's the only
726
+ // thing needed.
727
+ diag. span_suggestion_verbose ( span, msg, sugg, Applicability :: MachineApplicable ) ;
728
+ // This is redundant but needed because we won't enter the section with the
729
+ // additional note, so we point at the method call here too.
730
+ diag. span_label (
731
+ * call_span,
732
+ "calling this method introduces a `'static` lifetime requirement" ,
733
+ ) ;
734
+ } else if let hir:: LifetimeName :: ImplicitObjectLifetimeDefault
735
+ | hir:: LifetimeName :: Static = lt. res
736
+ {
737
+ // Otherwise, we add the right span for the note pointing at all the places where
738
+ // a `'static` requirement is introduced when invoking the method on this `impl`.
739
+ predicates. push ( lt. ident . span ) ;
740
+ }
741
+ } else if let ty:: Dynamic ( _, region, ty:: Dyn ) = ty. kind ( )
742
+ && * region == tcx. lifetimes . re_static
743
+ {
744
+ // The `self_ty` has a `'static` bound on a `dyn Trait`, either implicit or explicit,
745
+ // but we don't have access to the HIR to identify which one nor to provide a targetted
746
+ // enough `Span`, so instead we fall back to pointing at the `impl` header instead.
747
+ predicates. push ( tcx. def_span ( parent) ) ;
748
+ }
749
+ if !predicates. is_empty ( ) {
750
+ diag. span_label (
751
+ * call_span,
752
+ "calling this method introduces a `'static` lifetime requirement" ,
753
+ ) ;
754
+ let a_static_lt = if predicates. len ( ) == 1 {
755
+ "a `'static` lifetime requirement"
756
+ } else {
757
+ "`'static` lifetime requirements"
758
+ } ;
759
+ let span: MultiSpan = predicates. into ( ) ;
760
+ diag. span_note ( span, format ! ( "the `impl` on `{ty}` has {a_static_lt}" ) ) ;
761
+ }
762
+ }
763
+
557
764
/// Report a specialized error when `FnMut` closures return a reference to a captured variable.
558
765
/// This function expects `fr` to be local and `outlived_fr` to not be local.
559
766
///
@@ -793,7 +1000,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
793
1000
self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
794
1001
self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
795
1002
self . suggest_move_on_borrowing_closure ( & mut diag) ;
796
-
797
1003
diag
798
1004
}
799
1005
@@ -980,12 +1186,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
980
1186
"calling this method introduces the `impl`'s `'static` requirement" ,
981
1187
) ;
982
1188
err. subdiagnostic ( self . dcx ( ) , 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
- ) ;
1189
+ if let hir:: TyKind :: TraitObject ( traits, lt, Dyn ) = self_ty. kind
1190
+ && lt. res == hir:: LifetimeName :: ImplicitObjectLifetimeDefault
1191
+ && traits. iter ( ) . any ( |t| t. span == * span)
1192
+ {
1193
+ // We already handle the case where `self_ty` has an implicit 'static`
1194
+ // requirement specifically in `explain_impl_static_obligation`.
1195
+ } else {
1196
+ err. span_suggestion_verbose (
1197
+ span. shrink_to_hi ( ) ,
1198
+ "consider relaxing the implicit `'static` requirement" ,
1199
+ " + '_" ,
1200
+ Applicability :: MaybeIncorrect ,
1201
+ ) ;
1202
+ }
989
1203
suggested = true ;
990
1204
}
991
1205
}
0 commit comments