Skip to content

Commit 621d412

Browse files
yanchen4791dtolnay
yanchen4791
authored andcommitted
Fix invalid syntax in impl Trait parameter type suggestions for E0311
1 parent ef4046e commit 621d412

14 files changed

+365
-39
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+77-17
Original file line numberDiff line numberDiff line change
@@ -2144,18 +2144,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
21442144
// suggest adding an explicit lifetime bound to it.
21452145
let generics = self.tcx.generics_of(generic_param_scope);
21462146
// type_param_span is (span, has_bounds)
2147+
let mut is_synthetic = false;
2148+
let mut ast_generics = None;
21472149
let type_param_span = match bound_kind {
21482150
GenericKind::Param(ref param) => {
21492151
// Account for the case where `param` corresponds to `Self`,
21502152
// which doesn't have the expected type argument.
21512153
if !(generics.has_self && param.index == 0) {
21522154
let type_param = generics.type_param(param, self.tcx);
2155+
is_synthetic = type_param.kind.is_synthetic();
21532156
type_param.def_id.as_local().map(|def_id| {
21542157
// Get the `hir::Param` to verify whether it already has any bounds.
21552158
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
21562159
// instead we suggest `T: 'a + 'b` in that case.
21572160
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
2158-
let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
2161+
ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
21592162
let bounds =
21602163
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
21612164
// `sp` only covers `T`, change it so that it covers
@@ -2187,11 +2190,64 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
21872190
.unwrap_or("'lt".to_string())
21882191
};
21892192

2190-
let add_lt_sugg = generics
2191-
.params
2192-
.first()
2193-
.and_then(|param| param.def_id.as_local())
2194-
.map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));
2193+
let mut add_lt_suggs: Vec<Option<_>> = vec![];
2194+
if is_synthetic {
2195+
if let Some(ast_generics) = ast_generics {
2196+
let named_lifetime_param_exist = ast_generics.params.iter().any(|p| {
2197+
matches!(
2198+
p.kind,
2199+
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
2200+
)
2201+
});
2202+
if named_lifetime_param_exist && let [param, ..] = ast_generics.params
2203+
{
2204+
add_lt_suggs.push(Some((
2205+
self.tcx.def_span(param.def_id).shrink_to_lo(),
2206+
format!("{new_lt}, "),
2207+
)));
2208+
} else {
2209+
add_lt_suggs
2210+
.push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>"))));
2211+
}
2212+
}
2213+
} else {
2214+
if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local()
2215+
{
2216+
add_lt_suggs
2217+
.push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, "))));
2218+
}
2219+
}
2220+
2221+
if let Some(ast_generics) = ast_generics {
2222+
for p in ast_generics.params {
2223+
if p.is_elided_lifetime() {
2224+
if self
2225+
.tcx
2226+
.sess
2227+
.source_map()
2228+
.span_to_prev_source(p.span.shrink_to_hi())
2229+
.ok()
2230+
.map_or(false, |s| *s.as_bytes().last().unwrap() == b'&')
2231+
{
2232+
add_lt_suggs
2233+
.push(Some(
2234+
(
2235+
p.span.shrink_to_hi(),
2236+
if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span)
2237+
&& snip.starts_with(' ')
2238+
{
2239+
format!("{new_lt}")
2240+
} else {
2241+
format!("{new_lt} ")
2242+
}
2243+
)
2244+
));
2245+
} else {
2246+
add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>"))));
2247+
}
2248+
}
2249+
}
2250+
}
21952251

21962252
let labeled_user_string = match bound_kind {
21972253
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
@@ -2215,20 +2271,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22152271
);
22162272
}
22172273

2218-
fn binding_suggestion<S: fmt::Display>(
2274+
fn binding_suggestion<'tcx, S: fmt::Display>(
22192275
err: &mut Diagnostic,
22202276
type_param_span: Option<(Span, bool)>,
2221-
bound_kind: GenericKind<'_>,
2277+
bound_kind: GenericKind<'tcx>,
22222278
sub: S,
2223-
add_lt_sugg: Option<(Span, String)>,
2279+
add_lt_suggs: Vec<Option<(Span, String)>>,
22242280
) {
22252281
let msg = "consider adding an explicit lifetime bound";
22262282
if let Some((sp, has_lifetimes)) = type_param_span {
22272283
let suggestion =
22282284
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
22292285
let mut suggestions = vec![(sp, suggestion)];
2230-
if let Some(add_lt_sugg) = add_lt_sugg {
2231-
suggestions.push(add_lt_sugg);
2286+
for add_lt_sugg in add_lt_suggs {
2287+
if let Some(add_lt_sugg) = add_lt_sugg {
2288+
suggestions.push(add_lt_sugg);
2289+
}
22322290
}
22332291
err.multipart_suggestion_verbose(
22342292
format!("{msg}..."),
@@ -2252,9 +2310,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22522310
};
22532311
let mut sugg =
22542312
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
2255-
if let Some(lt) = add_lt_sugg.clone() {
2256-
sugg.push(lt);
2257-
sugg.rotate_right(1);
2313+
for add_lt_sugg in add_lt_suggs.clone() {
2314+
if let Some(lt) = add_lt_sugg {
2315+
sugg.push(lt);
2316+
sugg.rotate_right(1);
2317+
}
22582318
}
22592319
// `MaybeIncorrect` due to issue #41966.
22602320
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
@@ -2358,7 +2418,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23582418
// for the bound is not suitable for suggestions when `-Zverbose` is set because it
23592419
// uses `Debug` output, so we handle it specially here so that suggestions are
23602420
// always correct.
2361-
binding_suggestion(&mut err, type_param_span, bound_kind, name, None);
2421+
binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]);
23622422
err
23632423
}
23642424

@@ -2371,7 +2431,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23712431
"{} may not live long enough",
23722432
labeled_user_string
23732433
);
2374-
binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None);
2434+
binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]);
23752435
err
23762436
}
23772437

@@ -2410,7 +2470,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
24102470
type_param_span,
24112471
bound_kind,
24122472
new_lt,
2413-
add_lt_sugg,
2473+
add_lt_suggs,
24142474
);
24152475
}
24162476
}

tests/ui/error-codes/E0311.fixed

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
5+
fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
6+
with_restriction::<T>(x) //~ ERROR E0311
7+
}
8+
9+
fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
10+
x
11+
}
12+
13+
fn main() {}

tests/ui/error-codes/E0311.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
15
fn no_restriction<T>(x: &()) -> &() {
26
with_restriction::<T>(x) //~ ERROR E0311
37
}

tests/ui/error-codes/E0311.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
error[E0311]: the parameter type `T` may not live long enough
2-
--> $DIR/E0311.rs:2:5
2+
--> $DIR/E0311.rs:6:5
33
|
44
LL | with_restriction::<T>(x)
55
| ^^^^^^^^^^^^^^^^^^^^^
66
|
77
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
8-
--> $DIR/E0311.rs:1:25
8+
--> $DIR/E0311.rs:5:25
99
|
1010
LL | fn no_restriction<T>(x: &()) -> &() {
1111
| ^^^
1212
note: ...so that the type `T` will meet its required lifetime bounds
13-
--> $DIR/E0311.rs:2:5
13+
--> $DIR/E0311.rs:6:5
1414
|
1515
LL | with_restriction::<T>(x)
1616
| ^^^^^^^^^^^^^^^^^^^^^
1717
help: consider adding an explicit lifetime bound...
1818
|
19-
LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() {
20-
| +++ ++++
19+
LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
20+
| +++ ++++ ++
2121

2222
error: aborting due to previous error
2323

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
5+
fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
6+
with_restriction::<T>(x) //~ ERROR the parameter type `T` may not live long enough
7+
}
8+
9+
fn with_restriction<'b, T: 'b>(x: &'b ()) -> &'b () {
10+
x
11+
}
12+
13+
fn main() {}

tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
15
fn no_restriction<T>(x: &()) -> &() {
26
with_restriction::<T>(x) //~ ERROR the parameter type `T` may not live long enough
37
}

tests/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
error[E0311]: the parameter type `T` may not live long enough
2-
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5
2+
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5
33
|
44
LL | with_restriction::<T>(x)
55
| ^^^^^^^^^^^^^^^^^^^^^
66
|
77
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
8-
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:1:25
8+
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:5:25
99
|
1010
LL | fn no_restriction<T>(x: &()) -> &() {
1111
| ^^^
1212
note: ...so that the type `T` will meet its required lifetime bounds
13-
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5
13+
--> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:6:5
1414
|
1515
LL | with_restriction::<T>(x)
1616
| ^^^^^^^^^^^^^^^^^^^^^
1717
help: consider adding an explicit lifetime bound...
1818
|
19-
LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() {
20-
| +++ ++++
19+
LL | fn no_restriction<'a, T: 'a>(x: &'a ()) -> &() {
20+
| +++ ++++ ++
2121

2222
error: aborting due to previous error
2323

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
5+
fn foo<'a>(d: impl Sized + 'a, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
6+
//~^ HELP consider adding an explicit lifetime bound
7+
(d, p)
8+
//~^ ERROR the parameter type `impl Sized` may not live long enough
9+
//~| NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
10+
}
11+
12+
fn foo1<'b>(d: impl Sized + 'b, p: &'b mut ()) -> impl Sized + '_ {
13+
//~^ HELP consider adding an explicit lifetime bound...
14+
(d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
15+
//~^ ERROR the parameter type `impl Sized` may not live long enough
16+
}
17+
18+
fn foo2<'b, 'a>(d: impl Sized + 'a + 'b, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
19+
//~^ HELP consider adding an explicit lifetime bound
20+
(d, p)
21+
//~^ ERROR the parameter type `impl Sized + 'a` may not live long enough
22+
//~| NOTE ...so that the type `impl Sized + 'a` will meet its required lifetime bounds
23+
}
24+
25+
fn bar<'a, T : Sized + 'a>(d: T, p: &'a mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
26+
//~^ HELP consider adding an explicit lifetime bound
27+
(d, p)
28+
//~^ ERROR the parameter type `T` may not live long enough
29+
//~| NOTE ...so that the type `T` will meet its required lifetime bounds
30+
}
31+
32+
fn bar1<'b, T : Sized + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ {
33+
//~^ HELP consider adding an explicit lifetime bound...
34+
(d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds
35+
//~^ ERROR the parameter type `T` may not live long enough
36+
}
37+
38+
fn bar2<'b, 'a, T : Sized + 'a + 'b>(d: T, p: &'b mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
39+
//~^ HELP consider adding an explicit lifetime bound
40+
(d, p)
41+
//~^ ERROR the parameter type `T` may not live long enough
42+
//~| NOTE ...so that the type `T` will meet its required lifetime bounds
43+
}
44+
45+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// run-rustfix
2+
3+
#![allow(warnings)]
4+
5+
fn foo(d: impl Sized, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized` must be valid for the anonymous lifetime defined here...
6+
//~^ HELP consider adding an explicit lifetime bound
7+
(d, p)
8+
//~^ ERROR the parameter type `impl Sized` may not live long enough
9+
//~| NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
10+
}
11+
12+
fn foo1<'b>(d: impl Sized, p: &'b mut ()) -> impl Sized + '_ {
13+
//~^ HELP consider adding an explicit lifetime bound...
14+
(d, p) //~ NOTE ...so that the type `impl Sized` will meet its required lifetime bounds
15+
//~^ ERROR the parameter type `impl Sized` may not live long enough
16+
}
17+
18+
fn foo2<'a>(d: impl Sized + 'a, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `impl Sized + 'a` must be valid for the anonymous lifetime defined here...
19+
//~^ HELP consider adding an explicit lifetime bound
20+
(d, p)
21+
//~^ ERROR the parameter type `impl Sized + 'a` may not live long enough
22+
//~| NOTE ...so that the type `impl Sized + 'a` will meet its required lifetime bounds
23+
}
24+
25+
fn bar<T : Sized>(d: T, p: & mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
26+
//~^ HELP consider adding an explicit lifetime bound
27+
(d, p)
28+
//~^ ERROR the parameter type `T` may not live long enough
29+
//~| NOTE ...so that the type `T` will meet its required lifetime bounds
30+
}
31+
32+
fn bar1<'b, T : Sized>(d: T, p: &'b mut ()) -> impl Sized + '_ {
33+
//~^ HELP consider adding an explicit lifetime bound...
34+
(d, p) //~ NOTE ...so that the type `T` will meet its required lifetime bounds
35+
//~^ ERROR the parameter type `T` may not live long enough
36+
}
37+
38+
fn bar2<'a, T : Sized + 'a>(d: T, p: &mut ()) -> impl Sized + '_ { //~ NOTE the parameter type `T` must be valid for the anonymous lifetime defined here...
39+
//~^ HELP consider adding an explicit lifetime bound
40+
(d, p)
41+
//~^ ERROR the parameter type `T` may not live long enough
42+
//~| NOTE ...so that the type `T` will meet its required lifetime bounds
43+
}
44+
45+
fn main() {}

0 commit comments

Comments
 (0)