Skip to content

Commit ae02491

Browse files
committed
Better errors when we don't have implicit statics in trait objects
1 parent 3cd5ad5 commit ae02491

File tree

10 files changed

+155
-38
lines changed

10 files changed

+155
-38
lines changed

compiler/rustc_ast_lowering/src/path.rs

+1
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
336336
insertion_sp,
337337
suggestion,
338338
);
339+
err.note("assuming a `'static` lifetime...");
339340
err.emit();
340341
}
341342
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs

+33-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::infer::error_reporting::note_and_explain_region;
66
use crate::infer::lexical_region_resolve::RegionResolutionError;
77
use crate::infer::{SubregionOrigin, TypeTrace};
88
use crate::traits::ObligationCauseCode;
9+
use rustc_data_structures::stable_set::FxHashSet;
910
use rustc_errors::{Applicability, ErrorReported};
1011
use rustc_hir as hir;
1112
use rustc_hir::intravisit::Visitor;
@@ -42,13 +43,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
4243
multi_span
4344
.push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
4445
err.span_note(multi_span, "because this has an unmet lifetime requirement");
45-
note_and_explain_region(self.tcx(), &mut err, "...", sup, "...");
46+
note_and_explain_region(self.tcx(), &mut err, "", sup, "...");
4647
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
47-
let ty = self.tcx().type_of(*impl_def_id);
48-
let mut v = super::static_impl_trait::TraitObjectVisitor(vec![]);
49-
v.visit_ty(ty);
50-
let matching_def_ids = v.0;
48+
// If an impl is local, then maybe this isn't what they want. Try to
49+
// be as helpful as possible with implicit lifetimes.
5150

51+
// First, let's get the hir self type of the impl
5252
let impl_self_ty = match impl_node {
5353
hir::Node::Item(hir::Item {
5454
kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
@@ -57,26 +57,45 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
5757
_ => bug!("Node not an impl."),
5858
};
5959

60-
for matching_def_id in matching_def_ids {
60+
// Next, let's figure out the set of trait objects with implict static bounds
61+
let ty = self.tcx().type_of(*impl_def_id);
62+
let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
63+
v.visit_ty(ty);
64+
let mut traits = vec![];
65+
for matching_def_id in v.0 {
6166
let mut hir_v =
62-
super::static_impl_trait::HirTraitObjectVisitor(vec![], matching_def_id);
67+
super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
6368
hir_v.visit_ty(&impl_self_ty);
69+
}
6470

65-
let mut multi_span: MultiSpan = hir_v.0.clone().into();
66-
for span in &hir_v.0 {
67-
multi_span.push_span_label(
68-
*span,
69-
"this has an implicit `'static` lifetime requirement".to_string(),
70-
);
71+
if traits.is_empty() {
72+
// If there are no trait object traits to point at, either because
73+
// there aren't trait objects or because none are implicit, then just
74+
// write a single note on the impl itself.
75+
76+
let impl_span = self.tcx().def_span(*impl_def_id);
77+
err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
78+
} else {
79+
// Otherwise, point at all implicit static lifetimes
80+
81+
err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
82+
for span in &traits {
83+
err.span_note(*span, "this has an implicit `'static` lifetime requirement");
84+
// It would be nice to put this immediately under the above note, but they get
85+
// pushed to the end.
7186
err.span_suggestion_verbose(
7287
span.shrink_to_hi(),
7388
"consider relaxing the implicit `'static` requirement",
7489
" + '_".to_string(),
7590
Applicability::MaybeIncorrect,
7691
);
7792
}
78-
err.span_note(multi_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
7993
}
94+
} else {
95+
// Otherwise just point out the impl.
96+
97+
let impl_span = self.tcx().def_span(*impl_def_id);
98+
err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
8099
}
81100
err.emit();
82101
Some(ErrorReported)

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
44
use crate::infer::lexical_region_resolve::RegionResolutionError;
55
use crate::infer::{SubregionOrigin, TypeTrace};
66
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
7+
use rustc_data_structures::stable_set::FxHashSet;
78
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
89
use rustc_hir::def_id::DefId;
910
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
@@ -193,13 +194,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
193194
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
194195
// lifetime as above, but called using a fully-qualified path to the method:
195196
// `Foo::qux(bar)`.
196-
let mut v = TraitObjectVisitor(vec![]);
197+
let mut v = TraitObjectVisitor(FxHashSet::default());
197198
v.visit_ty(param.param_ty);
198199
if let Some((ident, self_ty)) =
199-
self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..])
200+
self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
200201
{
201-
if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty)
202-
{
202+
if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) {
203203
override_error_code = Some(ident);
204204
}
205205
}
@@ -340,7 +340,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
340340
fn get_impl_ident_and_self_ty_from_trait(
341341
&self,
342342
def_id: DefId,
343-
trait_objects: &[DefId],
343+
trait_objects: &FxHashSet<DefId>,
344344
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
345345
let tcx = self.tcx();
346346
match tcx.hir().get_if_local(def_id) {
@@ -377,9 +377,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
377377
// multiple `impl`s for the same trait like
378378
// `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
379379
// In that case, only the first one will get suggestions.
380-
let mut hir_v = HirTraitObjectVisitor(vec![], *did);
380+
let mut traits = vec![];
381+
let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
381382
hir_v.visit_ty(self_ty);
382-
!hir_v.0.is_empty()
383+
!traits.is_empty()
383384
}) =>
384385
{
385386
Some(self_ty)
@@ -421,33 +422,34 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
421422
_ => return false,
422423
};
423424

424-
let mut v = TraitObjectVisitor(vec![]);
425+
let mut v = TraitObjectVisitor(FxHashSet::default());
425426
v.visit_ty(ty);
426427

427428
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
428429
// `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
429430
let (ident, self_ty) =
430-
match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) {
431+
match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) {
431432
Some((ident, self_ty)) => (ident, self_ty),
432433
None => return false,
433434
};
434435

435436
// Find the trait object types in the argument, so we point at *only* the trait object.
436-
self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty)
437+
self.suggest_constrain_dyn_trait_in_impl(err, &v.0, ident, self_ty)
437438
}
438439

439440
fn suggest_constrain_dyn_trait_in_impl(
440441
&self,
441442
err: &mut DiagnosticBuilder<'_>,
442-
found_dids: &[DefId],
443+
found_dids: &FxHashSet<DefId>,
443444
ident: Ident,
444445
self_ty: &hir::Ty<'_>,
445446
) -> bool {
446447
let mut suggested = false;
447448
for found_did in found_dids {
448-
let mut hir_v = HirTraitObjectVisitor(vec![], *found_did);
449+
let mut traits = vec![];
450+
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
449451
hir_v.visit_ty(&self_ty);
450-
for span in &hir_v.0 {
452+
for span in &traits {
451453
let mut multi_span: MultiSpan = vec![*span].into();
452454
multi_span.push_span_label(
453455
*span,
@@ -472,14 +474,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
472474
}
473475

474476
/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
475-
pub(super) struct TraitObjectVisitor(pub(super) Vec<DefId>);
477+
pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
476478

477479
impl TypeVisitor<'_> for TraitObjectVisitor {
478480
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
479481
match t.kind() {
480482
ty::Dynamic(preds, RegionKind::ReStatic) => {
481483
if let Some(def_id) = preds.principal_def_id() {
482-
self.0.push(def_id);
484+
self.0.insert(def_id);
483485
}
484486
ControlFlow::CONTINUE
485487
}
@@ -489,9 +491,9 @@ impl TypeVisitor<'_> for TraitObjectVisitor {
489491
}
490492

491493
/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
492-
pub(super) struct HirTraitObjectVisitor(pub(super) Vec<Span>, pub(super) DefId);
494+
pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec<Span>, pub(super) DefId);
493495

494-
impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
496+
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
495497
type Map = ErasedMap<'tcx>;
496498

497499
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {

src/test/ui/async-await/async-fn-path-elision.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0726]: implicit elided lifetime not allowed here
33
|
44
LL | async fn error(lt: HasLifetime) {
55
| ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
6+
|
7+
= note: assuming a `'static` lifetime...
68

79
error: aborting due to previous error
810

src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs

+21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,28 @@ pub trait B {
1313
}
1414

1515
impl B for () {
16+
// `'a` doesn't match implicit `'static`: suggest `'_`
1617
type T<'a> = Box<dyn A + 'a>; //~ incompatible lifetime on type
1718
}
1819

20+
trait C {}
21+
impl C for Box<dyn A + 'static> {}
22+
pub trait D {
23+
type T<'a>: C;
24+
}
25+
impl D for () {
26+
// `'a` doesn't match explicit `'static`: we *should* suggest removing `'static`
27+
type T<'a> = Box<dyn A + 'a>; //~ incompatible lifetime on type
28+
}
29+
30+
trait E {}
31+
impl E for (Box<dyn A>, Box<dyn A>) {}
32+
pub trait F {
33+
type T<'a>: E;
34+
}
35+
impl F for () {
36+
// `'a` doesn't match explicit `'static`: suggest `'_`
37+
type T<'a> = (Box<dyn A + 'a>, Box<dyn A + 'a>); //~ incompatible lifetime on type
38+
}
39+
1940
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: incompatible lifetime on type
2-
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:16:5
2+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:5
33
|
44
LL | type T<'a> = Box<dyn A + 'a>;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,20 +9,79 @@ note: because this has an unmet lifetime requirement
99
|
1010
LL | type T<'a>: A;
1111
| ^ introduces a `'static` lifetime requirement
12-
note: ...the lifetime `'a` as defined on the associated item at 16:12...
13-
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:16:12
12+
note: the lifetime `'a` as defined on the associated item at 17:12...
13+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:12
1414
|
1515
LL | type T<'a> = Box<dyn A + 'a>;
1616
| ^^
17-
note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
17+
= note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
18+
note: this has an implicit `'static` lifetime requirement
1819
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:9:20
1920
|
2021
LL | impl A for Box<dyn A> {}
21-
| ^ this has an implicit `'static` lifetime requirement
22+
| ^
2223
help: consider relaxing the implicit `'static` requirement
2324
|
2425
LL | impl A for Box<dyn A + '_> {}
2526
| ^^^^
2627

27-
error: aborting due to previous error
28+
error: incompatible lifetime on type
29+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:5
30+
|
31+
LL | type T<'a> = Box<dyn A + 'a>;
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
|
34+
note: because this has an unmet lifetime requirement
35+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:23:17
36+
|
37+
LL | type T<'a>: C;
38+
| ^ introduces a `'static` lifetime requirement
39+
note: the lifetime `'a` as defined on the associated item at 27:12...
40+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:12
41+
|
42+
LL | type T<'a> = Box<dyn A + 'a>;
43+
| ^^
44+
note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
45+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:21:1
46+
|
47+
LL | impl C for Box<dyn A + 'static> {}
48+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
50+
error: incompatible lifetime on type
51+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:5
52+
|
53+
LL | type T<'a> = (Box<dyn A + 'a>, Box<dyn A + 'a>);
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
|
56+
note: because this has an unmet lifetime requirement
57+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:33:17
58+
|
59+
LL | type T<'a>: E;
60+
| ^ introduces a `'static` lifetime requirement
61+
note: the lifetime `'a` as defined on the associated item at 37:12...
62+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:12
63+
|
64+
LL | type T<'a> = (Box<dyn A + 'a>, Box<dyn A + 'a>);
65+
| ^^
66+
= note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
67+
note: this has an implicit `'static` lifetime requirement
68+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:31:21
69+
|
70+
LL | impl E for (Box<dyn A>, Box<dyn A>) {}
71+
| ^
72+
note: this has an implicit `'static` lifetime requirement
73+
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:31:33
74+
|
75+
LL | impl E for (Box<dyn A>, Box<dyn A>) {}
76+
| ^
77+
help: consider relaxing the implicit `'static` requirement
78+
|
79+
LL | impl E for (Box<dyn A + '_>, Box<dyn A>) {}
80+
| ^^^^
81+
help: consider relaxing the implicit `'static` requirement
82+
|
83+
LL | impl E for (Box<dyn A>, Box<dyn A + '_>) {}
84+
| ^^^^
85+
86+
error: aborting due to 3 previous errors
2887

src/test/ui/impl-header-lifetime-elision/path-elided.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0726]: implicit elided lifetime not allowed here
33
|
44
LL | impl MyTrait for Foo {
55
| ^^^- help: indicate the anonymous lifetime: `<'_>`
6+
|
7+
= note: assuming a `'static` lifetime...
68

79
error: aborting due to previous error
810

src/test/ui/impl-header-lifetime-elision/trait-elided.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0726]: implicit elided lifetime not allowed here
33
|
44
LL | impl MyTrait for u32 {
55
| ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
6+
|
7+
= note: assuming a `'static` lifetime...
68

79
error: aborting due to previous error
810

src/test/ui/issues/issue-10412.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ error[E0726]: implicit elided lifetime not allowed here
4545
|
4646
LL | impl<'self> Serializable<str> for &'self str {
4747
| ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
48+
|
49+
= note: assuming a `'static` lifetime...
4850

4951
error[E0277]: the size for values of type `str` cannot be known at compilation time
5052
--> $DIR/issue-10412.rs:6:13

src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0726]: implicit elided lifetime not allowed here
33
|
44
LL | impl Trait for Ref {}
55
| ^^^- help: indicate the anonymous lifetime: `<'_>`
6+
|
7+
= note: assuming a `'static` lifetime...
68

79
error: incompatible lifetime on type
810
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
@@ -15,11 +17,16 @@ note: because this has an unmet lifetime requirement
1517
|
1618
LL | pub struct Wrapper<T: Trait>(T);
1719
| ^^^^^ introduces a `'static` lifetime requirement
18-
note: ...the anonymous lifetime #1 defined on the method body at 16:5...
20+
note: the anonymous lifetime #1 defined on the method body at 16:5...
1921
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:5
2022
|
2123
LL | pub fn repro(_: Wrapper<Ref>);
2224
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25+
note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
26+
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:1
27+
|
28+
LL | impl Trait for Ref {}
29+
| ^^^^^^^^^^^^^^^^^^^^^
2330

2431
error: aborting due to 2 previous errors
2532

0 commit comments

Comments
 (0)