Skip to content

Commit 81c9094

Browse files
committed
Suggest substituting 'static lifetime in impl/dyn Trait + 'static return types
1 parent ff4a253 commit 81c9094

File tree

6 files changed

+232
-29
lines changed

6 files changed

+232
-29
lines changed

src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::infer::error_reporting::msg_span_from_free_region;
44
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
55
use crate::infer::lexical_region_resolve::RegionResolutionError;
66
use rustc_errors::{Applicability, ErrorReported};
7+
use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
78
use rustc_middle::ty::RegionKind;
89

910
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -20,8 +21,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2021
) = error.clone()
2122
{
2223
let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
23-
let (fn_return_span, is_dyn) =
24-
self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
24+
let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
25+
let is_dyn = matches!(fn_return.kind, TyKind::TraitObject(..));
26+
let fn_return_span = fn_return.span;
2527
if sub_r == &RegionKind::ReStatic {
2628
let sp = var_origin.span();
2729
let return_sp = sub_origin.span();
@@ -67,12 +69,58 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
6769
lifetime,
6870
);
6971
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
70-
err.span_suggestion_verbose(
71-
fn_return_span.shrink_to_hi(),
72-
&msg,
73-
format!(" + {}", lifetime_name),
74-
Applicability::MaybeIncorrect,
75-
);
72+
match fn_return.kind {
73+
TyKind::Def(item_id, _) => {
74+
let item = self.tcx().hir().item(item_id.id);
75+
let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
76+
opaque
77+
} else {
78+
err.emit();
79+
return Some(ErrorReported);
80+
};
81+
let (span, sugg) = opaque
82+
.bounds
83+
.iter()
84+
.filter_map(|arg| match arg {
85+
GenericBound::Outlives(Lifetime {
86+
name: LifetimeName::Static,
87+
span,
88+
..
89+
}) => Some((*span, lifetime_name.clone())),
90+
_ => None,
91+
})
92+
.next()
93+
.unwrap_or_else(|| {
94+
(
95+
fn_return_span.shrink_to_hi(),
96+
format!(" + {}", lifetime_name),
97+
)
98+
});
99+
100+
err.span_suggestion_verbose(
101+
span,
102+
&msg,
103+
sugg,
104+
Applicability::MaybeIncorrect,
105+
);
106+
}
107+
TyKind::TraitObject(_, lt) => {
108+
let (span, sugg) = match lt.name {
109+
LifetimeName::ImplicitObjectLifetimeDefault => (
110+
fn_return_span.shrink_to_hi(),
111+
format!(" + {}", lifetime_name),
112+
),
113+
_ => (lt.span, lifetime_name),
114+
};
115+
err.span_suggestion_verbose(
116+
span,
117+
&msg,
118+
sugg,
119+
Applicability::MaybeIncorrect,
120+
);
121+
}
122+
_ => {}
123+
}
76124
}
77125
err.emit();
78126
return Some(ErrorReported);

src/librustc_middle/ty/context.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,7 +1383,10 @@ impl<'tcx> TyCtxt<'tcx> {
13831383
})
13841384
}
13851385

1386-
pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
1386+
pub fn return_type_impl_or_dyn_trait(
1387+
&self,
1388+
scope_def_id: DefId,
1389+
) -> Option<&'tcx hir::Ty<'tcx>> {
13871390
let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
13881391
let hir_output = match self.hir().get(hir_id) {
13891392
Node::Item(hir::Item {
@@ -1429,15 +1432,17 @@ impl<'tcx> TyCtxt<'tcx> {
14291432
let output = self.erase_late_bound_regions(&sig.output());
14301433
if output.is_impl_trait() {
14311434
let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
1432-
Some((fn_decl.output.span(), false))
1435+
if let hir::FnRetTy::Return(ty) = fn_decl.output {
1436+
return Some(ty);
1437+
}
14331438
} else {
14341439
let mut v = TraitObjectVisitor(vec![]);
14351440
rustc_hir::intravisit::walk_ty(&mut v, hir_output);
14361441
if v.0.len() == 1 {
1437-
return Some((v.0[0], true));
1442+
return Some(v.0[0]);
14381443
}
1439-
None
14401444
}
1445+
None
14411446
}
14421447
_ => None,
14431448
}

src/librustc_middle/ty/diagnostics.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,21 +236,21 @@ pub fn suggest_constraining_type_param(
236236
}
237237
}
238238

239-
pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>);
240-
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
239+
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
240+
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
241241
type Map = rustc_hir::intravisit::ErasedMap<'v>;
242242

243243
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
244244
hir::intravisit::NestedVisitorMap::None
245245
}
246246

247-
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
247+
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
248248
if let hir::TyKind::TraitObject(
249249
_,
250250
hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
251251
) = ty.kind
252252
{
253-
self.0.push(ty.span);
253+
self.0.push(ty);
254254
}
255255
}
256256
}

src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,34 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
2626
| ^^^^^^^^^^^^^^
2727

2828
error: lifetime may not live long enough
29-
--> $DIR/must_outlive_least_region_or_bound.rs:12:69
29+
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
30+
|
31+
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
32+
| - ^ returning this value requires that `'1` must outlive `'static`
33+
| |
34+
| let's call the lifetime of this reference `'1`
35+
|
36+
= help: consider replacing `'1` with `'static`
37+
38+
error: lifetime may not live long enough
39+
--> $DIR/must_outlive_least_region_or_bound.rs:12:55
40+
|
41+
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
42+
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
43+
|
44+
= help: consider replacing `'a` with `'static`
45+
= help: consider replacing `'a` with `'static`
46+
47+
error[E0621]: explicit lifetime required in the type of `x`
48+
--> $DIR/must_outlive_least_region_or_bound.rs:15:41
49+
|
50+
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
51+
| ---- ^ lifetime `'a` required
52+
| |
53+
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
54+
55+
error: lifetime may not live long enough
56+
--> $DIR/must_outlive_least_region_or_bound.rs:33:69
3057
|
3158
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
3259
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
@@ -35,7 +62,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
3562
= help: consider replacing `'a` with `'static`
3663

3764
error: lifetime may not live long enough
38-
--> $DIR/must_outlive_least_region_or_bound.rs:17:61
65+
--> $DIR/must_outlive_least_region_or_bound.rs:38:61
3966
|
4067
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
4168
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -45,13 +72,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
4572
= help: consider adding the following bound: `'b: 'a`
4673

4774
error[E0310]: the parameter type `T` may not live long enough
48-
--> $DIR/must_outlive_least_region_or_bound.rs:22:51
75+
--> $DIR/must_outlive_least_region_or_bound.rs:43:51
4976
|
5077
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
5178
| ^^^^^^^^^^^^^^^^^^^^
5279
|
5380
= help: consider adding an explicit lifetime bound `T: 'static`...
5481

55-
error: aborting due to 5 previous errors
82+
error: aborting due to 8 previous errors
5683

57-
For more information about this error, try `rustc --explain E0310`.
84+
Some errors have detailed explanations: E0310, E0621.
85+
For more information about an error, try `rustc --explain E0310`.

src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@ fn elided(x: &i32) -> impl Copy { x }
66
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
77
//~^ ERROR cannot infer an appropriate lifetime
88

9+
fn elided2(x: &i32) -> impl Copy + 'static { x }
10+
//~^ ERROR cannot infer an appropriate lifetime
11+
12+
fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
13+
//~^ ERROR cannot infer an appropriate lifetime
14+
15+
fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
16+
//~^ ERROR explicit lifetime required in the type of `x`
17+
18+
fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
19+
//~^ ERROR cannot infer an appropriate lifetime
20+
21+
fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
22+
//~^ ERROR cannot infer an appropriate lifetime
23+
24+
fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
25+
//~^ ERROR explicit lifetime required in the type of `x`
26+
27+
fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
28+
//~^ ERROR cannot infer an appropriate lifetime
29+
930
trait LifetimeTrait<'a> {}
1031
impl<'a> LifetimeTrait<'a> for &'a i32 {}
1132

src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr

Lines changed: 109 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,57 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
2727
| ^^^^
2828

2929
error: cannot infer an appropriate lifetime
30-
--> $DIR/must_outlive_least_region_or_bound.rs:12:69
30+
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
31+
|
32+
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
33+
| ---- ------------------- ^ ...and is captured here
34+
| | |
35+
| | ...is required to be `'static` by this...
36+
| data with this lifetime...
37+
|
38+
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 9:1
39+
|
40+
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
41+
| ^^
42+
43+
error: cannot infer an appropriate lifetime
44+
--> $DIR/must_outlive_least_region_or_bound.rs:12:55
45+
|
46+
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
47+
| ------- ------------------- ^ ...and is captured here
48+
| | |
49+
| | ...is required to be `'static` by this...
50+
| data with this lifetime...
51+
|
52+
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:14
53+
|
54+
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
55+
| ^^
56+
57+
error[E0621]: explicit lifetime required in the type of `x`
58+
--> $DIR/must_outlive_least_region_or_bound.rs:15:24
59+
|
60+
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
61+
| ---- ^^^^^^^^^^^^^^ lifetime `'a` required
62+
| |
63+
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
64+
65+
error: cannot infer an appropriate lifetime
66+
--> $DIR/must_outlive_least_region_or_bound.rs:33:69
3167
|
3268
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
3369
| ------- -------------------------------- ^ ...and is captured here
3470
| | |
3571
| | ...is required to be `'static` by this...
3672
| data with this lifetime...
3773
|
38-
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15
74+
help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 33:15
3975
|
40-
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
41-
| ^^^^
76+
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
77+
| ^^
4278

4379
error[E0623]: lifetime mismatch
44-
--> $DIR/must_outlive_least_region_or_bound.rs:17:61
80+
--> $DIR/must_outlive_least_region_or_bound.rs:38:61
4581
|
4682
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
4783
| ------- ^^^^^^^^^^^^^^^^
@@ -50,14 +86,79 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
5086
| this parameter and the return type are declared with different lifetimes...
5187

5288
error[E0310]: the parameter type `T` may not live long enough
53-
--> $DIR/must_outlive_least_region_or_bound.rs:22:51
89+
--> $DIR/must_outlive_least_region_or_bound.rs:43:51
5490
|
5591
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
5692
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
5793
| |
5894
| help: consider adding an explicit lifetime bound...: `T: 'static +`
5995

60-
error: aborting due to 5 previous errors
96+
error: cannot infer an appropriate lifetime
97+
--> $DIR/must_outlive_least_region_or_bound.rs:18:50
98+
|
99+
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
100+
| ---- ---------^-
101+
| | | |
102+
| | | ...and is captured here
103+
| | ...is required to be `'static` by this...
104+
| data with this lifetime...
105+
|
106+
help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 18:1
107+
|
108+
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
109+
| ^^^^
110+
111+
error: cannot infer an appropriate lifetime
112+
--> $DIR/must_outlive_least_region_or_bound.rs:21:59
113+
|
114+
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
115+
| ------- ---------^-
116+
| | | |
117+
| | | ...and is captured here
118+
| | ...is required to be `'static` by this...
119+
| data with this lifetime...
120+
|
121+
help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 21:14
122+
|
123+
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
124+
| ^^^^
125+
126+
error[E0621]: explicit lifetime required in the type of `x`
127+
--> $DIR/must_outlive_least_region_or_bound.rs:24:51
128+
|
129+
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
130+
| ---- ^^^^^^^^^^^ lifetime `'static` required
131+
| |
132+
| help: add explicit lifetime `'static` to the type of `x`: `&'static i32`
133+
134+
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
135+
--> $DIR/must_outlive_least_region_or_bound.rs:27:69
136+
|
137+
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
138+
| ^
139+
|
140+
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 27:14...
141+
--> $DIR/must_outlive_least_region_or_bound.rs:27:14
142+
|
143+
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
144+
| ^^
145+
note: ...so that the expression is assignable
146+
--> $DIR/must_outlive_least_region_or_bound.rs:27:69
147+
|
148+
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
149+
| ^
150+
= note: expected `&i32`
151+
found `&'a i32`
152+
= note: but, the lifetime must be valid for the static lifetime...
153+
note: ...so that the expression is assignable
154+
--> $DIR/must_outlive_least_region_or_bound.rs:27:60
155+
|
156+
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
157+
| ^^^^^^^^^^^
158+
= note: expected `std::boxed::Box<(dyn std::fmt::Debug + 'static)>`
159+
found `std::boxed::Box<dyn std::fmt::Debug>`
160+
161+
error: aborting due to 12 previous errors
61162

62-
Some errors have detailed explanations: E0310, E0623.
163+
Some errors have detailed explanations: E0310, E0495, E0621, E0623.
63164
For more information about an error, try `rustc --explain E0310`.

0 commit comments

Comments
 (0)