Skip to content

Commit 1e193e9

Browse files
committed
Recovery from Fn, FnOnce, FnMut trait with named params
Signed-off-by: xizheyin <[email protected]>
1 parent 896cf80 commit 1e193e9

File tree

6 files changed

+106
-16
lines changed

6 files changed

+106
-16
lines changed

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ parse_float_literal_requires_integer_part = float literals must have an integer
272272
273273
parse_float_literal_unsupported_base = {$base} float literal is not supported
274274
275+
parse_fn_path_found_named_params = `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
276+
.suggestion = remove name of the param
277+
275278
parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
276279
.label = `async` because of this
277280
.suggestion = remove the `async` qualifier

compiler/rustc_parse/src/errors.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,14 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
15911591
pub fn_token_span: Span,
15921592
}
15931593

1594+
#[derive(Diagnostic)]
1595+
#[diag(parse_fn_path_found_named_params)]
1596+
pub(crate) struct FnPathFoundNamedParams {
1597+
#[primary_span]
1598+
#[suggestion(applicability = "machine-applicable", code = "")]
1599+
pub named_param_span: Span,
1600+
}
1601+
15941602
#[derive(Diagnostic)]
15951603
#[diag(parse_path_double_colon)]
15961604
pub(crate) struct PathSingleColon {

compiler/rustc_parse/src/parser/ty.rs

+58-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use thin_vec::{ThinVec, thin_vec};
1414
use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
1515
use crate::errors::{
1616
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
17-
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
18-
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
19-
NestedCVariadicType, ReturnTypesUseThinArrow,
17+
FnPathFoundNamedParams, FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics,
18+
FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut,
19+
NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow,
2020
};
2121
use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
2222

@@ -1203,6 +1203,8 @@ impl<'a> Parser<'a> {
12031203

12041204
err.emit();
12051205

1206+
path
1207+
} else if let Some(path) = self.recover_path_for_fn_or_fn_onece_or_fn_mut() {
12061208
path
12071209
} else {
12081210
self.parse_path(PathStyle::Type)?
@@ -1268,6 +1270,59 @@ impl<'a> Parser<'a> {
12681270
}
12691271
}
12701272

1273+
/// Recover Fn(usize) from Fn(x: usize)
1274+
fn recover_path_for_fn_or_fn_onece_or_fn_mut(&mut self) -> Option<ast::Path> {
1275+
if !(self.token.is_ident_named(sym::FnOnce)
1276+
|| self.token.is_ident_named(sym::FnMut)
1277+
|| self.token.is_ident_named(sym::Fn))
1278+
|| !self.look_ahead(1, |t| *t == TokenKind::OpenParen)
1279+
{
1280+
return None;
1281+
}
1282+
1283+
let fn_token_span = self.token.span;
1284+
let snapshot = self.create_snapshot_for_diagnostic();
1285+
self.bump();
1286+
let args_lo = self.token.span;
1287+
1288+
match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::No) {
1289+
Ok(decl) => {
1290+
for param in &decl.inputs {
1291+
if !matches!(param.pat.kind, crate::ast::PatKind::Missing) {
1292+
self.dcx()
1293+
.emit_err(FnPathFoundNamedParams { named_param_span: param.pat.span });
1294+
1295+
return Some(ast::Path {
1296+
span: fn_token_span.to(self.prev_token.span),
1297+
segments: thin_vec![ast::PathSegment {
1298+
ident: Ident::new(sym::Fn, fn_token_span),
1299+
id: DUMMY_NODE_ID,
1300+
args: Some(P(ast::GenericArgs::Parenthesized(
1301+
ast::ParenthesizedArgs {
1302+
span: args_lo.to(self.prev_token.span),
1303+
inputs: decl
1304+
.inputs
1305+
.iter()
1306+
.map(|param| { param.ty.clone() })
1307+
.collect(),
1308+
inputs_span: args_lo.until(decl.output.span()),
1309+
output: decl.output.clone(),
1310+
}
1311+
))),
1312+
}],
1313+
tokens: None,
1314+
});
1315+
}
1316+
}
1317+
}
1318+
Err(diag) => {
1319+
diag.cancel();
1320+
}
1321+
}
1322+
self.restore_snapshot(snapshot);
1323+
None
1324+
}
1325+
12711326
/// Optionally parses `for<$generic_params>`.
12721327
pub(super) fn parse_late_bound_lifetime_defs(
12731328
&mut self,
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn g(_: fn(a: u8)) {}
2-
fn x(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
3-
fn y(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
4-
fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} //~ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
2+
fn x(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
3+
fn y(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
4+
fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {} //~ ERROR `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
55

66
fn main(){}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
2-
--> $DIR/fn-trait-use-named-params-issue-140169.rs:2:25
1+
error: `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
2+
--> $DIR/fn-trait-use-named-params-issue-140169.rs:2:21
33
|
44
LL | fn x(_: impl Fn(u8, vvvv: u8)) {}
5-
| ^ expected one of 7 possible tokens
5+
| ^^^^ help: remove name of the param
66

7-
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
8-
--> $DIR/fn-trait-use-named-params-issue-140169.rs:3:21
7+
error: `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
8+
--> $DIR/fn-trait-use-named-params-issue-140169.rs:3:17
99
|
1010
LL | fn y(_: impl Fn(aaaa: u8, u8)) {}
11-
| ^ expected one of 7 possible tokens
11+
| ^^^^ help: remove name of the param
1212

13-
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
14-
--> $DIR/fn-trait-use-named-params-issue-140169.rs:4:21
13+
error: `Fn`, `FnMut`, `FnOnce`-trait syntax does not allow named arguments
14+
--> $DIR/fn-trait-use-named-params-issue-140169.rs:4:17
1515
|
1616
LL | fn z(_: impl Fn(aaaa: u8, vvvv: u8)) {}
17-
| ^ expected one of 7 possible tokens
17+
| ^^^^ help: remove name of the param
1818

1919
error: aborting due to 3 previous errors
2020

tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr

+25-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,36 @@ help: try adding parentheses
99
LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
1010
| + +
1111

12+
error: ambiguous `+` in a type
13+
--> $DIR/impl-fn-parsing-ambiguities.rs:4:27
14+
|
15+
LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
16+
| ^^^^^^^^^^^^^^^
17+
|
18+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
help: try adding parentheses
20+
|
21+
LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
22+
| + +
23+
24+
error: ambiguous `+` in a type
25+
--> $DIR/impl-fn-parsing-ambiguities.rs:10:24
26+
|
27+
LL | fn b() -> impl Fn() -> impl Debug + Send {
28+
| ^^^^^^^^^^^^^^^^^
29+
|
30+
help: try adding parentheses
31+
|
32+
LL | fn b() -> impl Fn() -> (impl Debug + Send) {
33+
| + +
34+
1235
error: ambiguous `+` in a type
1336
--> $DIR/impl-fn-parsing-ambiguities.rs:10:24
1437
|
1538
LL | fn b() -> impl Fn() -> impl Debug + Send {
1639
| ^^^^^^^^^^^^^^^^^
1740
|
41+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1842
help: try adding parentheses
1943
|
2044
LL | fn b() -> impl Fn() -> (impl Debug + Send) {
@@ -32,6 +56,6 @@ note: lifetime declared here
3256
LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
3357
| ^
3458

35-
error: aborting due to 3 previous errors
59+
error: aborting due to 5 previous errors
3660

3761
For more information about this error, try `rustc --explain E0657`.

0 commit comments

Comments
 (0)