From d6ce3269b4031a8c8fb0fab7710bad7165642fcf Mon Sep 17 00:00:00 2001 From: Andrew Hickman Date: Mon, 6 Sep 2021 23:30:20 +0100 Subject: [PATCH 1/2] Suggest wapping expr in parentheses on invalid unary negation Fixes #88701 --- compiler/rustc_typeck/src/check/op.rs | 78 ++++++++++++++------------ src/test/ui/parser/expr-as-stmt.fixed | 5 ++ src/test/ui/parser/expr-as-stmt.rs | 5 ++ src/test/ui/parser/expr-as-stmt.stderr | 26 ++++++++- 4 files changed, 77 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 9b495fba1975d..bc5587af3efb6 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -680,42 +680,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ex.span, format!("cannot apply unary operator `{}`", op.as_str()), ); - match actual.kind() { - Uint(_) if op == hir::UnOp::Neg => { - err.note("unsigned values cannot be negated"); - - if let hir::ExprKind::Unary( - _, - hir::Expr { - kind: - hir::ExprKind::Lit(Spanned { - node: ast::LitKind::Int(1, _), - .. - }), - .. - }, - ) = ex.kind - { - err.span_suggestion( - ex.span, - &format!( - "you may have meant the maximum value of `{}`", - actual - ), - format!("{}::MAX", actual), - Applicability::MaybeIncorrect, - ); + + let sp = self.tcx.sess.source_map().start_point(ex.span); + if let Some(sp) = + self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) + { + self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); + } else { + match actual.kind() { + Uint(_) if op == hir::UnOp::Neg => { + err.note("unsigned values cannot be negated"); + + if let hir::ExprKind::Unary( + _, + hir::Expr { + kind: + hir::ExprKind::Lit(Spanned { + node: ast::LitKind::Int(1, _), + .. + }), + .. + }, + ) = ex.kind + { + err.span_suggestion( + ex.span, + &format!( + "you may have meant the maximum value of `{}`", + actual + ), + format!("{}::MAX", actual), + Applicability::MaybeIncorrect, + ); + } + } + Str | Never | Char | Tuple(_) | Array(_, _) => {} + Ref(_, ref lty, _) if *lty.kind() == Str => {} + _ => { + let missing_trait = match op { + hir::UnOp::Neg => "std::ops::Neg", + hir::UnOp::Not => "std::ops::Not", + hir::UnOp::Deref => "std::ops::UnDerf", + }; + suggest_impl_missing(&mut err, operand_ty, &missing_trait); } - } - Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, ref lty, _) if *lty.kind() == Str => {} - _ => { - let missing_trait = match op { - hir::UnOp::Neg => "std::ops::Neg", - hir::UnOp::Not => "std::ops::Not", - hir::UnOp::Deref => "std::ops::UnDerf", - }; - suggest_impl_missing(&mut err, operand_ty, &missing_trait); } } err.emit(); diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed index c217ab9774fd2..941fd29d0a319 100644 --- a/src/test/ui/parser/expr-as-stmt.fixed +++ b/src/test/ui/parser/expr-as-stmt.fixed @@ -32,4 +32,9 @@ fn moo(x: u32) -> bool { }) > 0 //~ ERROR expected expression } +fn qux() -> u32 { + ({2}) - 2 //~ ERROR cannot apply unary operator `-` to type `u32` + //~^ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs index b04025faaec63..0a60ad601207a 100644 --- a/src/test/ui/parser/expr-as-stmt.rs +++ b/src/test/ui/parser/expr-as-stmt.rs @@ -32,4 +32,9 @@ fn moo(x: u32) -> bool { } > 0 //~ ERROR expected expression } +fn qux() -> u32 { + {2} - 2 //~ ERROR cannot apply unary operator `-` to type `u32` + //~^ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index ba5cd01abfcc7..0a04c2c8995f9 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -99,7 +99,29 @@ help: parentheses are required to parse this as an expression LL | ({ 3 }) * 3 | + + -error: aborting due to 9 previous errors +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:36:6 + | +LL | {2} - 2 + | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | {return 2;} - 2 + | ++++++ + + +error[E0600]: cannot apply unary operator `-` to type `u32` + --> $DIR/expr-as-stmt.rs:36:9 + | +LL | {2} - 2 + | ^^^ cannot apply unary operator `-` + | +help: parentheses are required to parse this as an expression + | +LL | ({2}) - 2 + | + + + +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0308, E0614. +Some errors have detailed explanations: E0308, E0600, E0614. For more information about an error, try `rustc --explain E0308`. From 43b79d8ef5e1967a7ea476b757256d62fdbb3ebf Mon Sep 17 00:00:00 2001 From: Andrew Hickman Date: Sat, 11 Sep 2021 10:08:11 +0100 Subject: [PATCH 2/2] Add comment pointing to test --- compiler/rustc_typeck/src/check/op.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index bc5587af3efb6..a574a63d63b28 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -685,6 +685,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { + // If the previous expression was a block expression, suggest parentheses + // (turning this into a binary subtraction operation instead.) + // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp); } else { match actual.kind() {