use super::pat::{GateOr, PARAM_EXPECTED};
-use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType};
use super::{SemiColonMode, SeqSep, TokenExpectType};
use crate::maybe_recover_from_interpolated_ty_qpath;
self.expect_or()?;
args
};
- let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverFatArrow::Yes)?;
+ let output =
+ self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
Ok(P(FnDecl { inputs, output }))
}
// Parse type with mandatory colon and (possibly empty) bounds,
// or with mandatory equality sign and the second type.
- let ty = self.parse_ty()?;
+ let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) {
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
-use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{FollowedByType, Parser, PathStyle};
use crate::maybe_whole;
let header = self.parse_fn_front_matter()?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
- let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)`
+ let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
let mut sig_hi = self.prev_token.span;
&mut self,
req_name: ReqName,
ret_allow_plus: AllowPlus,
+ recover_return_sign: RecoverReturnSign,
) -> PResult<'a, P<FnDecl>> {
Ok(P(FnDecl {
inputs: self.parse_fn_params(req_name)?,
- output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, RecoverFatArrow::Yes)?,
+ output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?,
}))
}
-use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath};
+use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, TokenType};
use crate::maybe_whole;
use rustc_ast::ptr::P;
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let span = ident.span.to(self.prev_token.span);
let output =
- self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?;
+ self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
ParenthesizedArgs { inputs, output, span }.into()
};
No,
}
-#[derive(PartialEq)]
-pub(super) enum RecoverFatArrow {
+#[derive(Copy, Clone, PartialEq)]
+pub(super) enum RecoverReturnSign {
Yes,
+ OnlyFatArrow,
No,
}
+impl RecoverReturnSign {
+ fn can_recover(self, token: &TokenKind) -> bool {
+ match self {
+ Self::Yes => matches!(token, token::FatArrow | token::Colon),
+ Self::OnlyFatArrow => matches!(token, token::FatArrow),
+ Self::No => false,
+ }
+ }
+}
+
// Is `...` (`CVarArgs`) legal at this level of type parsing?
#[derive(PartialEq)]
enum AllowCVariadic {
impl<'a> Parser<'a> {
/// Parses a type.
pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No)
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ RecoverQPath::Yes,
+ AllowCVariadic::No,
+ RecoverReturnSign::Yes,
+ )
}
/// Parse a type suitable for a function or function pointer parameter.
/// The difference from `parse_ty` is that this version allows `...`
/// (`CVarArgs`) at the top level of the type.
pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes)
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ RecoverQPath::Yes,
+ AllowCVariadic::Yes,
+ RecoverReturnSign::Yes,
+ )
}
/// Parses a type in restricted contexts where `+` is not permitted.
/// Example 2: `value1 as TYPE + value2`
/// `+` is prohibited to avoid interactions with expression grammar.
pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No)
+ self.parse_ty_common(
+ AllowPlus::No,
+ RecoverQPath::Yes,
+ AllowCVariadic::No,
+ RecoverReturnSign::Yes,
+ )
+ }
+
+ /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
+ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ RecoverQPath::Yes,
+ AllowCVariadic::Yes,
+ RecoverReturnSign::OnlyFatArrow,
+ )
}
/// Parses an optional return type `[ -> TY ]` in a function declaration.
&mut self,
allow_plus: AllowPlus,
recover_qpath: RecoverQPath,
- recover_fat_arrow: RecoverFatArrow,
+ recover_return_sign: RecoverReturnSign,
) -> PResult<'a, FnRetTy> {
Ok(if self.eat(&token::RArrow) {
// 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,
+ recover_return_sign,
+ )?;
FnRetTy::Ty(ty)
- } else if recover_fat_arrow == RecoverFatArrow::Yes && self.token == token::FatArrow {
+ } else if recover_return_sign.can_recover(&self.token.kind) {
// Don't `eat` to prevent `=>` from being added as an expected token which isn't
// actually expected and could only confuse users
self.bump();
Applicability::MachineApplicable,
)
.emit();
- let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
+ let ty = self.parse_ty_common(
+ allow_plus,
+ recover_qpath,
+ AllowCVariadic::No,
+ recover_return_sign,
+ )?;
FnRetTy::Ty(ty)
} else {
FnRetTy::Default(self.token.span.shrink_to_lo())
allow_plus: AllowPlus,
recover_qpath: RecoverQPath,
allow_c_variadic: AllowCVariadic,
+ recover_return_sign: RecoverReturnSign,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
TyKind::Infer
} else if self.check_fn_front_matter() {
// Function pointer type
- self.parse_ty_bare_fn(lo, Vec::new())?
+ self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)?
} else if self.check_keyword(kw::For) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
if self.check_fn_front_matter() {
- self.parse_ty_bare_fn(lo, lifetime_defs)?
+ self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
/// Function Style ABI Parameter types
/// ```
/// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.
- fn parse_ty_bare_fn(&mut self, lo: Span, params: Vec<GenericParam>) -> PResult<'a, TyKind> {
+ fn parse_ty_bare_fn(
+ &mut self,
+ lo: Span,
+ params: Vec<GenericParam>,
+ recover_return_sign: RecoverReturnSign,
+ ) -> PResult<'a, TyKind> {
let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
- let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
+ let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
if let ast::Const::Yes(span) = constness {
self.error_fn_ptr_bad_qualifier(whole_span, span, "const");
+++ /dev/null
-// 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() {
-}
+++ /dev/null
-// 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() {
-}
+++ /dev/null
-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
-
+++ /dev/null
-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));
-}
+++ /dev/null
-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
-
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+fn a() -> usize { 0 }
+//~^ ERROR return types are denoted using `->`
+
+fn b()-> 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() {
+ let foo = |a: bool| -> bool { a };
+ //~^ ERROR return types are denoted using `->`
+ dbg!(foo(false));
+
+ let bar = |a: bool|-> bool { a };
+ //~^ ERROR return types are denoted using `->`
+ dbg!(bar(false));
+}
--- /dev/null
+// run-rustfix
+#![allow(unused)]
+fn a() => usize { 0 }
+//~^ ERROR return types are denoted using `->`
+
+fn b(): 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() {
+ let foo = |a: bool| => bool { a };
+ //~^ ERROR return types are denoted using `->`
+ dbg!(foo(false));
+
+ let bar = |a: bool|: bool { a };
+ //~^ ERROR return types are denoted using `->`
+ dbg!(bar(false));
+}
--- /dev/null
+error: return types are denoted using `->`
+ --> $DIR/fn-recover-return-sign.rs:3:8
+ |
+LL | fn a() => usize { 0 }
+ | ^^ help: use `->` instead
+
+error: return types are denoted using `->`
+ --> $DIR/fn-recover-return-sign.rs:6:7
+ |
+LL | fn b(): usize { 0 }
+ | ^ help: use `->` instead
+
+error: return types are denoted using `->`
+ --> $DIR/fn-recover-return-sign.rs:21:25
+ |
+LL | let foo = |a: bool| => bool { a };
+ | ^^ help: use `->` instead
+
+error: return types are denoted using `->`
+ --> $DIR/fn-recover-return-sign.rs:25:24
+ |
+LL | let bar = |a: bool|: bool { a };
+ | ^ help: use `->` instead
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// Separate test file because `Fn() => bool` isn't getting fixed and rustfix complained that
+// even though a fix was applied the code was still incorrect
+
+fn foo() => impl Fn() => bool {
+ //~^ ERROR return types are denoted using `->`
+ //~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
+ unimplemented!()
+}
--- /dev/null
+error: return types are denoted using `->`
+ --> $DIR/fn-recover-return-sign2.rs:4:10
+ |
+LL | fn foo() => impl Fn() => bool {
+ | ^^ help: use `->` instead
+
+error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
+ --> $DIR/fn-recover-return-sign2.rs:4:23
+ |
+LL | fn foo() => impl Fn() => bool {
+ | ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{`
+
+error: aborting due to 2 previous errors
+
-fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
+fn foo(x: i32): i32 {
+//~^ ERROR return types are denoted using `->`
x
}
-error: expected one of `->`, `;`, `where`, or `{`, found `:`
+error: return types are denoted using `->`
--> $DIR/fn-colon-return-type.rs:1:15
|
LL | fn foo(x: i32): i32 {
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ help: use `->` instead
error: aborting due to previous error
fn f(a: isize, b: isize) : lt(a, b) { }
-//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:`
+//~^ ERROR return types are denoted using `->`
+//~| ERROR expected type, found function `lt` [E0573]
+//~| ERROR expected type, found local variable `a` [E0573]
+//~| ERROR expected type, found local variable `b` [E0573]
fn lt(a: isize, b: isize) { }
-fn main() { let a: isize = 10; let b: isize = 23; check (lt(a, b)); f(a, b); }
+fn main() {
+ let a: isize = 10;
+ let b: isize = 23;
+ check (lt(a, b));
+ //~^ ERROR cannot find function `check` in this scope [E0425]
+ f(a, b);
+}
-error: expected one of `->`, `;`, `where`, or `{`, found `:`
+error: return types are denoted using `->`
--> $DIR/not-a-pred.rs:1:26
|
LL | fn f(a: isize, b: isize) : lt(a, b) { }
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ help: use `->` instead
-error: aborting due to previous error
+error[E0573]: expected type, found function `lt`
+ --> $DIR/not-a-pred.rs:1:28
+ |
+LL | fn f(a: isize, b: isize) : lt(a, b) { }
+ | ^^^^^^^^ not a type
+
+error[E0573]: expected type, found local variable `a`
+ --> $DIR/not-a-pred.rs:1:31
+ |
+LL | fn f(a: isize, b: isize) : lt(a, b) { }
+ | ^ not a type
+
+error[E0573]: expected type, found local variable `b`
+ --> $DIR/not-a-pred.rs:1:34
+ |
+LL | fn f(a: isize, b: isize) : lt(a, b) { }
+ | ^ not a type
+
+error[E0425]: cannot find function `check` in this scope
+ --> $DIR/not-a-pred.rs:12:5
+ |
+LL | check (lt(a, b));
+ | ^^^^^ not found in this scope
+
+error: aborting due to 5 previous errors
+Some errors have detailed explanations: E0425, E0573.
+For more information about an error, try `rustc --explain E0425`.