Gracefully handle mistyping -> as => in function return type
This commit is contained in:
parent
c4926d01ad
commit
5404deeb64
9 changed files with 96 additions and 6 deletions
|
@ -1,5 +1,5 @@
|
||||||
use super::pat::{GateOr, PARAM_EXPECTED};
|
use super::pat::{GateOr, PARAM_EXPECTED};
|
||||||
use super::ty::{AllowPlus, RecoverQPath};
|
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
|
||||||
use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType};
|
use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType};
|
||||||
use super::{SemiColonMode, SeqSep, TokenExpectType};
|
use super::{SemiColonMode, SeqSep, TokenExpectType};
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
|
@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_or()?;
|
self.expect_or()?;
|
||||||
args
|
args
|
||||||
};
|
};
|
||||||
let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?;
|
let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?;
|
||||||
|
|
||||||
Ok(P(FnDecl { inputs, output }))
|
Ok(P(FnDecl { inputs, output }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
|
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
|
||||||
use super::ty::{AllowPlus, RecoverQPath};
|
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
|
||||||
use super::{FollowedByType, Parser, PathStyle};
|
use super::{FollowedByType, Parser, PathStyle};
|
||||||
|
|
||||||
use crate::maybe_whole;
|
use crate::maybe_whole;
|
||||||
|
@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> {
|
||||||
) -> PResult<'a, P<FnDecl>> {
|
) -> PResult<'a, P<FnDecl>> {
|
||||||
Ok(P(FnDecl {
|
Ok(P(FnDecl {
|
||||||
inputs: self.parse_fn_params(req_name)?,
|
inputs: self.parse_fn_params(req_name)?,
|
||||||
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
|
output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::ty::{AllowPlus, RecoverQPath};
|
use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
|
||||||
use super::{Parser, TokenType};
|
use super::{Parser, TokenType};
|
||||||
use crate::maybe_whole;
|
use crate::maybe_whole;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
|
@ -231,7 +231,8 @@ impl<'a> Parser<'a> {
|
||||||
// `(T, U) -> R`
|
// `(T, U) -> R`
|
||||||
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
|
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
|
||||||
let span = ident.span.to(self.prev_token.span);
|
let span = ident.span.to(self.prev_token.span);
|
||||||
let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?;
|
let output =
|
||||||
|
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?;
|
||||||
ParenthesizedArgs { inputs, output, span }.into()
|
ParenthesizedArgs { inputs, output, span }.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,12 @@ pub(super) enum RecoverQPath {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub(super) enum RecoverFatArrow {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
// Is `...` (`CVarArgs`) legal at this level of type parsing?
|
// Is `...` (`CVarArgs`) legal at this level of type parsing?
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum AllowCVariadic {
|
enum AllowCVariadic {
|
||||||
|
@ -87,11 +93,26 @@ impl<'a> Parser<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
allow_plus: AllowPlus,
|
allow_plus: AllowPlus,
|
||||||
recover_qpath: RecoverQPath,
|
recover_qpath: RecoverQPath,
|
||||||
|
recover_fat_arrow: RecoverFatArrow,
|
||||||
) -> PResult<'a, FnRetTy> {
|
) -> PResult<'a, FnRetTy> {
|
||||||
Ok(if self.eat(&token::RArrow) {
|
Ok(if self.eat(&token::RArrow) {
|
||||||
// FIXME(Centril): Can we unconditionally `allow_plus`?
|
// FIXME(Centril): Can we unconditionally `allow_plus`?
|
||||||
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
|
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
|
||||||
FnRetTy::Ty(ty)
|
FnRetTy::Ty(ty)
|
||||||
|
} else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow {
|
||||||
|
// Don't `eat` to prevent `=>` from being added as an expected token which isn't
|
||||||
|
// actually expected and could only confuse users
|
||||||
|
self.bump();
|
||||||
|
self.struct_span_err(self.prev_token.span, "return types are denoted using `->`")
|
||||||
|
.span_suggestion_short(
|
||||||
|
self.prev_token.span,
|
||||||
|
"use `->` instead",
|
||||||
|
"->".to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
|
||||||
|
FnRetTy::Ty(ty)
|
||||||
} else {
|
} else {
|
||||||
FnRetTy::Default(self.token.span.shrink_to_lo())
|
FnRetTy::Default(self.token.span.shrink_to_lo())
|
||||||
})
|
})
|
||||||
|
|
18
src/test/ui/fn/fn-fat-arrow-return.fixed
Normal file
18
src/test/ui/fn/fn-fat-arrow-return.fixed
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused)]
|
||||||
|
fn a() -> usize { 0 }
|
||||||
|
//~^ ERROR return types are denoted using `->`
|
||||||
|
|
||||||
|
fn bar(_: u32) {}
|
||||||
|
|
||||||
|
fn baz() -> *const dyn Fn(u32) { unimplemented!() }
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
match () {
|
||||||
|
_ if baz() == &bar as &dyn Fn(u32) => (),
|
||||||
|
() => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
18
src/test/ui/fn/fn-fat-arrow-return.rs
Normal file
18
src/test/ui/fn/fn-fat-arrow-return.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused)]
|
||||||
|
fn a() => usize { 0 }
|
||||||
|
//~^ ERROR return types are denoted using `->`
|
||||||
|
|
||||||
|
fn bar(_: u32) {}
|
||||||
|
|
||||||
|
fn baz() -> *const dyn Fn(u32) { unimplemented!() }
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
match () {
|
||||||
|
_ if baz() == &bar as &dyn Fn(u32) => (),
|
||||||
|
() => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
8
src/test/ui/fn/fn-fat-arrow-return.stderr
Normal file
8
src/test/ui/fn/fn-fat-arrow-return.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
error: return types are denoted using `->`
|
||||||
|
--> $DIR/fn-fat-arrow-return.rs:3:8
|
||||||
|
|
|
||||||
|
LL | fn a() => usize { 0 }
|
||||||
|
| ^^ help: use `->` instead
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
10
src/test/ui/fn/fn-fat-arrow-return2.rs
Normal file
10
src/test/ui/fn/fn-fat-arrow-return2.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fn a() => impl Fn() => bool {
|
||||||
|
//~^ ERROR return types are denoted using `->`
|
||||||
|
//~| ERROR expected `;` or `{`, found `=>`
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = |a: bool| => bool { a };
|
||||||
|
dbg!(foo(false));
|
||||||
|
}
|
14
src/test/ui/fn/fn-fat-arrow-return2.stderr
Normal file
14
src/test/ui/fn/fn-fat-arrow-return2.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: return types are denoted using `->`
|
||||||
|
--> $DIR/fn-fat-arrow-return2.rs:1:8
|
||||||
|
|
|
||||||
|
LL | fn a() => impl Fn() => bool {
|
||||||
|
| ^^ help: use `->` instead
|
||||||
|
|
||||||
|
error: expected `;` or `{`, found `=>`
|
||||||
|
--> $DIR/fn-fat-arrow-return2.rs:1:21
|
||||||
|
|
|
||||||
|
LL | fn a() => impl Fn() => bool {
|
||||||
|
| ^^ expected `;` or `{`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue