From 5404deeb64f4449079f5165ace6bfa1e52ca4b33 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Wed, 14 Oct 2020 22:27:48 +0200 Subject: [PATCH 1/3] Gracefully handle mistyping -> as => in function return type --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/item.rs | 4 ++-- compiler/rustc_parse/src/parser/path.rs | 5 +++-- compiler/rustc_parse/src/parser/ty.rs | 21 +++++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.fixed | 18 ++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.rs | 18 ++++++++++++++++++ src/test/ui/fn/fn-fat-arrow-return.stderr | 8 ++++++++ src/test/ui/fn/fn-fat-arrow-return2.rs | 10 ++++++++++ src/test/ui/fn/fn-fat-arrow-return2.stderr | 14 ++++++++++++++ 9 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/fn/fn-fat-arrow-return.fixed create mode 100644 src/test/ui/fn/fn-fat-arrow-return.rs create mode 100644 src/test/ui/fn/fn-fat-arrow-return.stderr create mode 100644 src/test/ui/fn/fn-fat-arrow-return2.rs create mode 100644 src/test/ui/fn/fn-fat-arrow-return2.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93be478fc8c2c..790a0c867af8b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ 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::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; @@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> { self.expect_or()?; 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 })) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5954b370e6d98..9e342a0d68131 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error}; -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; @@ -1648,7 +1648,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { Ok(P(FnDecl { 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)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 17e5bcf760504..311a4829fcfc5 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -use super::ty::{AllowPlus, RecoverQPath}; +use super::ty::{AllowPlus, RecoverFatArrow, RecoverQPath}; use super::{Parser, TokenType}; use crate::maybe_whole; use rustc_ast::ptr::P; @@ -231,7 +231,8 @@ impl<'a> Parser<'a> { // `(T, U) -> R` 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)?; + let output = + self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverFatArrow::No)?; ParenthesizedArgs { inputs, output, span }.into() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 7a6ebca4e1541..ff19c5cfa8564 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,12 @@ pub(super) enum RecoverQPath { No, } +#[derive(PartialEq)] +pub(super) enum RecoverFatArrow { + Yes, + No, +} + // Is `...` (`CVarArgs`) legal at this level of type parsing? #[derive(PartialEq)] enum AllowCVariadic { @@ -87,11 +93,26 @@ impl<'a> Parser<'a> { &mut self, allow_plus: AllowPlus, recover_qpath: RecoverQPath, + recover_fat_arrow: RecoverFatArrow, ) -> 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)?; 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 { FnRetTy::Default(self.token.span.shrink_to_lo()) }) diff --git a/src/test/ui/fn/fn-fat-arrow-return.fixed b/src/test/ui/fn/fn-fat-arrow-return.fixed new file mode 100644 index 0000000000000..0acca85aa679f --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.fixed @@ -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() { +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.rs b/src/test/ui/fn/fn-fat-arrow-return.rs new file mode 100644 index 0000000000000..4bdcd70d7fc43 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.rs @@ -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() { +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.stderr b/src/test/ui/fn/fn-fat-arrow-return.stderr new file mode 100644 index 0000000000000..1fcdb18a51472 --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return.stderr @@ -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 + diff --git a/src/test/ui/fn/fn-fat-arrow-return2.rs b/src/test/ui/fn/fn-fat-arrow-return2.rs new file mode 100644 index 0000000000000..316fa2cbf02ed --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return2.rs @@ -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)); +} diff --git a/src/test/ui/fn/fn-fat-arrow-return2.stderr b/src/test/ui/fn/fn-fat-arrow-return2.stderr new file mode 100644 index 0000000000000..a6f9fe3b5732c --- /dev/null +++ b/src/test/ui/fn/fn-fat-arrow-return2.stderr @@ -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 + From 3548be94c03fd6d1c11afd6af9c884f398a6489e Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 15 Oct 2020 21:21:45 +0200 Subject: [PATCH 2/3] Gracefully handle confusing -> with : in function return type --- compiler/rustc_parse/src/parser/expr.rs | 5 +- compiler/rustc_parse/src/parser/generics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 7 +- compiler/rustc_parse/src/parser/path.rs | 4 +- compiler/rustc_parse/src/parser/ty.rs | 78 +++++++++++++++---- src/test/ui/fn/fn-fat-arrow-return.fixed | 18 ----- src/test/ui/fn/fn-fat-arrow-return.stderr | 8 -- src/test/ui/fn/fn-fat-arrow-return2.rs | 10 --- src/test/ui/fn/fn-fat-arrow-return2.stderr | 14 ---- src/test/ui/fn/fn-recover-return-sign.fixed | 28 +++++++ ...ow-return.rs => fn-recover-return-sign.rs} | 10 +++ src/test/ui/fn/fn-recover-return-sign.stderr | 26 +++++++ src/test/ui/fn/fn-recover-return-sign2.rs | 8 ++ src/test/ui/fn/fn-recover-return-sign2.stderr | 14 ++++ src/test/ui/parser/fn-colon-return-type.rs | 3 +- .../ui/parser/fn-colon-return-type.stderr | 4 +- src/test/ui/parser/not-a-pred.rs | 13 +++- src/test/ui/parser/not-a-pred.stderr | 32 +++++++- 18 files changed, 205 insertions(+), 79 deletions(-) delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.fixed delete mode 100644 src/test/ui/fn/fn-fat-arrow-return.stderr delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.rs delete mode 100644 src/test/ui/fn/fn-fat-arrow-return2.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign.fixed rename src/test/ui/fn/{fn-fat-arrow-return.rs => fn-recover-return-sign.rs} (50%) create mode 100644 src/test/ui/fn/fn-recover-return-sign.stderr create mode 100644 src/test/ui/fn/fn-recover-return-sign2.rs create mode 100644 src/test/ui/fn/fn-recover-return-sign2.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 790a0c867af8b..4d2167442bed6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ 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; @@ -1647,7 +1647,8 @@ impl<'a> Parser<'a> { 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 })) } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index dd99a7587dd54..ed8d4f78426ac 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -240,7 +240,7 @@ impl<'a> Parser<'a> { // 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 { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9e342a0d68131..ff0323a107a74 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,5 +1,5 @@ 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; @@ -1514,7 +1514,7 @@ impl<'a> Parser<'a> { 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; @@ -1645,10 +1645,11 @@ impl<'a> Parser<'a> { &mut self, req_name: ReqName, ret_allow_plus: AllowPlus, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { 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)?, })) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 311a4829fcfc5..4510e86e0341f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,4 +1,4 @@ -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; @@ -232,7 +232,7 @@ impl<'a> Parser<'a> { 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() }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ff19c5cfa8564..ee0dc8f6304a7 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,12 +43,23 @@ pub(super) enum RecoverQPath { 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 { @@ -68,14 +79,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - 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> { - 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. @@ -85,7 +106,22 @@ impl<'a> Parser<'a> { /// 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> { - 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> { + self.parse_ty_common( + AllowPlus::Yes, + RecoverQPath::Yes, + AllowCVariadic::Yes, + RecoverReturnSign::OnlyFatArrow, + ) } /// Parses an optional return type `[ -> TY ]` in a function declaration. @@ -93,13 +129,18 @@ impl<'a> Parser<'a> { &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(); @@ -111,7 +152,12 @@ impl<'a> Parser<'a> { 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()) @@ -123,6 +169,7 @@ impl<'a> Parser<'a> { allow_plus: AllowPlus, recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -150,14 +197,14 @@ impl<'a> Parser<'a> { 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(); @@ -359,9 +406,14 @@ impl<'a> Parser<'a> { /// 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) -> PResult<'a, TyKind> { + fn parse_ty_bare_fn( + &mut self, + lo: Span, + params: Vec, + 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"); diff --git a/src/test/ui/fn/fn-fat-arrow-return.fixed b/src/test/ui/fn/fn-fat-arrow-return.fixed deleted file mode 100644 index 0acca85aa679f..0000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// 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() { -} diff --git a/src/test/ui/fn/fn-fat-arrow-return.stderr b/src/test/ui/fn/fn-fat-arrow-return.stderr deleted file mode 100644 index 1fcdb18a51472..0000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return.stderr +++ /dev/null @@ -1,8 +0,0 @@ -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 - diff --git a/src/test/ui/fn/fn-fat-arrow-return2.rs b/src/test/ui/fn/fn-fat-arrow-return2.rs deleted file mode 100644 index 316fa2cbf02ed..0000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.rs +++ /dev/null @@ -1,10 +0,0 @@ -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)); -} diff --git a/src/test/ui/fn/fn-fat-arrow-return2.stderr b/src/test/ui/fn/fn-fat-arrow-return2.stderr deleted file mode 100644 index a6f9fe3b5732c..0000000000000 --- a/src/test/ui/fn/fn-fat-arrow-return2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -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 - diff --git a/src/test/ui/fn/fn-recover-return-sign.fixed b/src/test/ui/fn/fn-recover-return-sign.fixed new file mode 100644 index 0000000000000..076be6a35a4b7 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.fixed @@ -0,0 +1,28 @@ +// 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)); +} diff --git a/src/test/ui/fn/fn-fat-arrow-return.rs b/src/test/ui/fn/fn-recover-return-sign.rs similarity index 50% rename from src/test/ui/fn/fn-fat-arrow-return.rs rename to src/test/ui/fn/fn-recover-return-sign.rs index 4bdcd70d7fc43..0656023c0f898 100644 --- a/src/test/ui/fn/fn-fat-arrow-return.rs +++ b/src/test/ui/fn/fn-recover-return-sign.rs @@ -3,6 +3,9 @@ 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!() } @@ -15,4 +18,11 @@ fn foo() { } 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)); } diff --git a/src/test/ui/fn/fn-recover-return-sign.stderr b/src/test/ui/fn/fn-recover-return-sign.stderr new file mode 100644 index 0000000000000..983109730ff3c --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign.stderr @@ -0,0 +1,26 @@ +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 + diff --git a/src/test/ui/fn/fn-recover-return-sign2.rs b/src/test/ui/fn/fn-recover-return-sign2.rs new file mode 100644 index 0000000000000..b6a6a1ec2a6ed --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.rs @@ -0,0 +1,8 @@ +// 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!() +} diff --git a/src/test/ui/fn/fn-recover-return-sign2.stderr b/src/test/ui/fn/fn-recover-return-sign2.stderr new file mode 100644 index 0000000000000..d62cacd4bf531 --- /dev/null +++ b/src/test/ui/fn/fn-recover-return-sign2.stderr @@ -0,0 +1,14 @@ +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 + diff --git a/src/test/ui/parser/fn-colon-return-type.rs b/src/test/ui/parser/fn-colon-return-type.rs index c791fb3ae6749..0001ef57c9902 100644 --- a/src/test/ui/parser/fn-colon-return-type.rs +++ b/src/test/ui/parser/fn-colon-return-type.rs @@ -1,4 +1,5 @@ -fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` +fn foo(x: i32): i32 { +//~^ ERROR return types are denoted using `->` x } diff --git a/src/test/ui/parser/fn-colon-return-type.stderr b/src/test/ui/parser/fn-colon-return-type.stderr index 92df9bc60bd3c..1de9187820560 100644 --- a/src/test/ui/parser/fn-colon-return-type.stderr +++ b/src/test/ui/parser/fn-colon-return-type.stderr @@ -1,8 +1,8 @@ -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 diff --git a/src/test/ui/parser/not-a-pred.rs b/src/test/ui/parser/not-a-pred.rs index 1b3d9bf66bb60..5518b554d8e53 100644 --- a/src/test/ui/parser/not-a-pred.rs +++ b/src/test/ui/parser/not-a-pred.rs @@ -1,6 +1,15 @@ 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); +} diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index ec413c5594c44..bcc64a687fd0c 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,34 @@ -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`. From e916641fd35bddabc8b018a5e51fe23b93875c66 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Thu, 17 Dec 2020 13:44:08 +0100 Subject: [PATCH 3/3] Address review comments --- compiler/rustc_parse/src/parser/ty.rs | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index ee0dc8f6304a7..9553f5d09e83b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -43,6 +43,16 @@ pub(super) enum RecoverQPath { No, } +/// Signals whether parsing a type should recover `->`. +/// +/// More specifically, when parsing a function like: +/// ```rust +/// fn foo() => u8 { 0 } +/// fn bar(): u8 { 0 } +/// ``` +/// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling +/// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8` +/// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty` #[derive(Copy, Clone, PartialEq)] pub(super) enum RecoverReturnSign { Yes, @@ -51,6 +61,10 @@ pub(super) enum RecoverReturnSign { } impl RecoverReturnSign { + /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`, + /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering + /// colons can cause problems when parsing where clauses), and + /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow fn can_recover(self, token: &TokenKind) -> bool { match self { Self::Yes => matches!(token, token::FatArrow | token::Colon), @@ -81,8 +95,8 @@ impl<'a> Parser<'a> { pub fn parse_ty(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -93,8 +107,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -108,8 +122,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::No, - RecoverQPath::Yes, AllowCVariadic::No, + RecoverQPath::Yes, RecoverReturnSign::Yes, ) } @@ -118,8 +132,8 @@ impl<'a> Parser<'a> { pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P> { self.parse_ty_common( AllowPlus::Yes, - RecoverQPath::Yes, AllowCVariadic::Yes, + RecoverQPath::Yes, RecoverReturnSign::OnlyFatArrow, ) } @@ -135,8 +149,8 @@ impl<'a> Parser<'a> { // FIXME(Centril): Can we unconditionally `allow_plus`? let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -154,8 +168,8 @@ impl<'a> Parser<'a> { .emit(); let ty = self.parse_ty_common( allow_plus, - recover_qpath, AllowCVariadic::No, + recover_qpath, recover_return_sign, )?; FnRetTy::Ty(ty) @@ -167,8 +181,8 @@ impl<'a> Parser<'a> { fn parse_ty_common( &mut self, allow_plus: AllowPlus, - recover_qpath: RecoverQPath, allow_c_variadic: AllowCVariadic, + recover_qpath: RecoverQPath, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, P> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;