Skip to content

Commit 5404dee

Browse files
committed
Gracefully handle mistyping -> as => in function return type
1 parent c4926d0 commit 5404dee

9 files changed

+96
-6
lines changed

compiler/rustc_parse/src/parser/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::pat::{GateOr, PARAM_EXPECTED};
2-
use super::ty::{AllowPlus, RecoverQPath};
2+
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
33
use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType};
44
use super::{SemiColonMode, SeqSep, TokenExpectType};
55
use crate::maybe_recover_from_interpolated_ty_qpath;
@@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> {
16471647
self.expect_or()?;
16481648
args
16491649
};
1650-
let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?;
1650+
let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?;
16511651

16521652
Ok(P(FnDecl { inputs, output }))
16531653
}

compiler/rustc_parse/src/parser/item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
2-
use super::ty::{AllowPlus, RecoverQPath};
2+
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
33
use super::{FollowedByType, Parser, PathStyle};
44

55
use crate::maybe_whole;
@@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> {
16481648
) -> PResult<'a, P<FnDecl>> {
16491649
Ok(P(FnDecl {
16501650
inputs: self.parse_fn_params(req_name)?,
1651-
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
1651+
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?,
16521652
}))
16531653
}
16541654

compiler/rustc_parse/src/parser/path.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::ty::{AllowPlus, RecoverQPath};
1+
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
22
use super::{Parser, TokenType};
33
use crate::maybe_whole;
44
use rustc_ast::ptr::P;
@@ -231,7 +231,8 @@ impl<'a> Parser<'a> {
231231
// `(T, U) -> R`
232232
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
233233
let span = ident.span.to(self.prev_token.span);
234-
let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?;
234+
let output =
235+
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?;
235236
ParenthesizedArgs { inputs, output, span }.into()
236237
};
237238

compiler/rustc_parse/src/parser/ty.rs

+21
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ pub(super) enum RecoverQPath {
4343
No,
4444
}
4545

46+
#[derive(PartialEq)]
47+
pub(super) enum RecoverFatArrow {
48+
Yes,
49+
No,
50+
}
51+
4652
// Is `...` (`CVarArgs`) legal at this level of type parsing?
4753
#[derive(PartialEq)]
4854
enum AllowCVariadic {
@@ -87,11 +93,26 @@ impl<'a> Parser<'a> {
8793
&mut self,
8894
allow_plus: AllowPlus,
8995
recover_qpath: RecoverQPath,
96+
recover_fat_arrow: RecoverFatArrow,
9097
) -> PResult<'a, FnRetTy> {
9198
Ok(if self.eat(&token::RArrow) {
9299
// FIXME(Centril): Can we unconditionally `allow_plus`?
93100
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
94101
FnRetTy::Ty(ty)
102+
} else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow {
103+
// Don't `eat` to prevent `=>` from being added as an expected token which isn't
104+
// actually expected and could only confuse users
105+
self.bump();
106+
self.struct_span_err(self.prev_token.span, "return types are denoted using `->`")
107+
.span_suggestion_short(
108+
self.prev_token.span,
109+
"use `->` instead",
110+
"->".to_string(),
111+
Applicability::MachineApplicable,
112+
)
113+
.emit();
114+
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
115+
FnRetTy::Ty(ty)
95116
} else {
96117
FnRetTy::Default(self.token.span.shrink_to_lo())
97118
})
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
fn a() -> usize { 0 }
4+
//~^ ERROR return types are denoted using `->`
5+
6+
fn bar(_: u32) {}
7+
8+
fn baz() -> *const dyn Fn(u32) { unimplemented!() }
9+
10+
fn foo() {
11+
match () {
12+
_ if baz() == &bar as &dyn Fn(u32) => (),
13+
() => (),
14+
}
15+
}
16+
17+
fn main() {
18+
}

src/test/ui/fn/fn-fat-arrow-return.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
fn a() => usize { 0 }
4+
//~^ ERROR return types are denoted using `->`
5+
6+
fn bar(_: u32) {}
7+
8+
fn baz() -> *const dyn Fn(u32) { unimplemented!() }
9+
10+
fn foo() {
11+
match () {
12+
_ if baz() == &bar as &dyn Fn(u32) => (),
13+
() => (),
14+
}
15+
}
16+
17+
fn main() {
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: return types are denoted using `->`
2+
--> $DIR/fn-fat-arrow-return.rs:3:8
3+
|
4+
LL | fn a() => usize { 0 }
5+
| ^^ help: use `->` instead
6+
7+
error: aborting due to previous error
8+
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn a() => impl Fn() => bool {
2+
//~^ ERROR return types are denoted using `->`
3+
//~| ERROR expected `;` or `{`, found `=>`
4+
unimplemented!()
5+
}
6+
7+
fn main() {
8+
let foo = |a: bool| => bool { a };
9+
dbg!(foo(false));
10+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: return types are denoted using `->`
2+
--> $DIR/fn-fat-arrow-return2.rs:1:8
3+
|
4+
LL | fn a() => impl Fn() => bool {
5+
| ^^ help: use `->` instead
6+
7+
error: expected `;` or `{`, found `=>`
8+
--> $DIR/fn-fat-arrow-return2.rs:1:21
9+
|
10+
LL | fn a() => impl Fn() => bool {
11+
| ^^ expected `;` or `{`
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)