From ba61fe432a13e63ea81112dd63d60b28cc63b40e Mon Sep 17 00:00:00 2001 From: Duddino Date: Fri, 17 Apr 2020 14:07:44 +0200 Subject: [PATCH 1/4] Account for use of `try!()` in 2018 edition and guide users in the right direction --- src/librustc_parse/parser/diagnostics.rs | 33 ++++++++++++++++++++++++ src/librustc_parse/parser/expr.rs | 2 ++ src/test/ui/try-macro-suggestion.rs | 9 +++++++ src/test/ui/try-macro-suggestion.stderr | 30 +++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 src/test/ui/try-macro-suggestion.rs create mode 100644 src/test/ui/try-macro-suggestion.stderr diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 12b9b68268248..06122df304d8d 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1054,6 +1054,39 @@ impl<'a> Parser<'a> { } } + pub(super) fn try_macro_suggestion(&mut self) -> DiagnosticBuilder<'a> { + let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for ! + let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(token::Paren)); //check for ( + + if is_questionmark && is_open { + let lo = self.token.span; + self.bump(); //remove try + self.bump(); //remove ! + let try_span = lo.to(self.token.span); //we take the try!( span + self.bump(); //remove ( + let is_empty = self.token == token::CloseDelim(token::Paren); //check if the block is empty + self.consume_block(token::Paren, ConsumeClosingDelim::No); //eat the block + let hi = self.token.span; + self.bump(); //remove ) + let mut err = self.struct_span_err(lo.to(hi), "use of deprecated `try` macro"); + err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated"); + if !is_empty { + err.multipart_suggestion( + "you can use the `?` operator instead", + vec![(try_span, "".to_owned()), (hi, "?".to_owned())], + Applicability::MachineApplicable, + ); + err.span_suggestion(lo.shrink_to_lo(), "alternatively, you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable); + } else { + //if the try! macro is empty, it isn't possible to suggest something using the `?` operator + err.span_suggestion(lo.shrink_to_lo(), "you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable); + } + err + } else { + self.expected_expression_found() // The user isn't trying to invoke the try! macro + } + } + /// Recovers a situation like `for ( $pat in $expr )` /// and suggest writing `for $pat in $expr` instead. /// diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 4e3c5fa63de2c..907a8c2dce20f 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1001,11 +1001,13 @@ impl<'a> Parser<'a> { fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; + let is_try = self.token.is_keyword(kw::Try); match self.parse_opt_lit() { Some(literal) => { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); self.maybe_recover_from_bad_qpath(expr, true) } + None if is_try => Err(self.try_macro_suggestion()), None => Err(self.expected_expression_found()), } } diff --git a/src/test/ui/try-macro-suggestion.rs b/src/test/ui/try-macro-suggestion.rs new file mode 100644 index 0000000000000..635ceac0b199e --- /dev/null +++ b/src/test/ui/try-macro-suggestion.rs @@ -0,0 +1,9 @@ +// compile-flags: --edition 2018 +fn foo() -> Result<(), ()> { + Ok(try!()); //~ ERROR use of deprecated `try` macro + Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro +} + +fn main() { + let _ = foo(); +} diff --git a/src/test/ui/try-macro-suggestion.stderr b/src/test/ui/try-macro-suggestion.stderr new file mode 100644 index 0000000000000..9d833ef5ed9fb --- /dev/null +++ b/src/test/ui/try-macro-suggestion.stderr @@ -0,0 +1,30 @@ +error: use of deprecated `try` macro + --> $DIR/try-macro-suggestion.rs:3:8 + | +LL | Ok(try!()); + | ^^^^^^ + | + = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated +help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax + | +LL | Ok(r#try!()); + | ^^ + +error: use of deprecated `try` macro + --> $DIR/try-macro-suggestion.rs:4:8 + | +LL | Ok(try!(Ok(()))) + | ^^^^^^^^^^^^ + | + = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated +help: you can use the `?` operator instead + | +LL | Ok(Ok(())?) + | -- ^ +help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax + | +LL | Ok(r#try!(Ok(()))) + | ^^ + +error: aborting due to 2 previous errors + From d3f5c274c6990db429b934212f1d9efd101104e3 Mon Sep 17 00:00:00 2001 From: Duddino Date: Fri, 17 Apr 2020 18:26:39 +0200 Subject: [PATCH 2/4] Moved is_try check into try_macro_suggestion --- src/librustc_parse/parser/diagnostics.rs | 3 ++- src/librustc_parse/parser/expr.rs | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 06122df304d8d..a79e1a44e96ba 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1055,10 +1055,11 @@ impl<'a> Parser<'a> { } pub(super) fn try_macro_suggestion(&mut self) -> DiagnosticBuilder<'a> { + let is_try = self.token.is_keyword(kw::Try); let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for ! let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(token::Paren)); //check for ( - if is_questionmark && is_open { + if is_try && is_questionmark && is_open { let lo = self.token.span; self.bump(); //remove try self.bump(); //remove ! diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 907a8c2dce20f..ef98aab9c9f90 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1001,14 +1001,12 @@ impl<'a> Parser<'a> { fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; - let is_try = self.token.is_keyword(kw::Try); match self.parse_opt_lit() { Some(literal) => { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); self.maybe_recover_from_bad_qpath(expr, true) } - None if is_try => Err(self.try_macro_suggestion()), - None => Err(self.expected_expression_found()), + None => Err(self.try_macro_suggestion()), } } From 67128f1e4a880dd8c364f38e919bac19afb08282 Mon Sep 17 00:00:00 2001 From: Duddino Date: Fri, 17 Apr 2020 19:10:29 +0200 Subject: [PATCH 3/4] Improved try_macro_suggestion --- src/librustc_parse/parser/diagnostics.rs | 7 ++++--- src/librustc_parse/parser/expr.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index a79e1a44e96ba..e2b8da64dc76c 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1054,7 +1054,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn try_macro_suggestion(&mut self) -> DiagnosticBuilder<'a> { + pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P> { let is_try = self.token.is_keyword(kw::Try); let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for ! let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(token::Paren)); //check for ( @@ -1082,9 +1082,10 @@ impl<'a> Parser<'a> { //if the try! macro is empty, it isn't possible to suggest something using the `?` operator err.span_suggestion(lo.shrink_to_lo(), "you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable); } - err + err.emit(); + Ok(self.mk_expr_err(lo.to(hi))) } else { - self.expected_expression_found() // The user isn't trying to invoke the try! macro + Err(self.expected_expression_found()) // The user isn't trying to invoke the try! macro } } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index ef98aab9c9f90..986f5410e26c0 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1006,7 +1006,7 @@ impl<'a> Parser<'a> { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); self.maybe_recover_from_bad_qpath(expr, true) } - None => Err(self.try_macro_suggestion()), + None => self.try_macro_suggestion(), } } From 79abac863e6ef0077d70063518bd34a20f75eae6 Mon Sep 17 00:00:00 2001 From: Duddino Date: Fri, 17 Apr 2020 19:29:36 +0200 Subject: [PATCH 4/4] Improved try_macro_suggestion function --- src/librustc_parse/parser/diagnostics.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index e2b8da64dc76c..552f3d798ae8a 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1071,17 +1071,15 @@ impl<'a> Parser<'a> { self.bump(); //remove ) let mut err = self.struct_span_err(lo.to(hi), "use of deprecated `try` macro"); err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated"); + let prefix = if is_empty { "" } else { "alternatively, " }; if !is_empty { err.multipart_suggestion( "you can use the `?` operator instead", vec![(try_span, "".to_owned()), (hi, "?".to_owned())], Applicability::MachineApplicable, ); - err.span_suggestion(lo.shrink_to_lo(), "alternatively, you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable); - } else { - //if the try! macro is empty, it isn't possible to suggest something using the `?` operator - err.span_suggestion(lo.shrink_to_lo(), "you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", "r#".to_string(), Applicability::MachineApplicable); } + err.span_suggestion(lo.shrink_to_lo(), &format!("{}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", prefix), "r#".to_string(), Applicability::MachineApplicable); err.emit(); Ok(self.mk_expr_err(lo.to(hi))) } else {