From 2969137a727d3fe2fea36c3a022ccb04b9b02617 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 May 2017 21:34:59 +0200 Subject: [PATCH] Add invalid unary operator usage error code --- src/librustc_typeck/check/op.rs | 10 +++-- src/librustc_typeck/diagnostics.rs | 43 ++++++++++++++++++++ src/test/compile-fail/E0600.rs | 13 ++++++ src/test/ui/codemap_tests/issue-28308.stderr | 2 +- src/test/ui/reachable/expr_unary.stderr | 2 +- 5 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/E0600.rs diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 59cb61d9b97f0..3709260acc997 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -316,10 +316,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.lookup_op_method(ex, operand_ty, vec![], mname, trait_did, operand_expr) { Ok(t) => t, Err(()) => { - self.type_error_message(ex.span, |actual| { - format!("cannot apply unary operator `{}` to type `{}`", - op_str, actual) - }, operand_ty); + let actual = self.resolve_type_vars_if_possible(&operand_ty); + if !actual.references_error() { + struct_span_err!(self.tcx.sess, ex.span, E0600, + "cannot apply unary operator `{}` to type `{}`", + op_str, actual).emit(); + } self.tcx.types.err } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 612aa5a1f0dce..f19eb19427611 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4052,6 +4052,49 @@ x.chocolate(); // error: no method named `chocolate` found for type `Mouth` ``` "##, +E0600: r##" +An unary operator was used on a type which doesn't implement it. + +Example of erroneous code: + +```compile_fail,E0600 +enum Question { + Yes, + No, +} + +!Question::Yes; // error: cannot apply unary operator `!` to type `Question` +``` + +In this case, `Question` would need to implement the `std::ops::Not` trait in +order to be able to use `!` on it. Let's implement it: + +``` +use std::ops::Not; + +enum Question { + Yes, + No, +} + +// We implement the `Not` trait on the enum. +impl Not for Question { + type Output = bool; + + fn not(self) -> bool { + match self { + Question::Yes => false, // If the `Answer` is `Yes`, then it + // returns false. + Question::No => true, // And here we do the opposite. + } + } +} + +assert_eq!(!Question::Yes, false); +assert_eq!(!Question::No, true); +``` +"##, + } register_diagnostics! { diff --git a/src/test/compile-fail/E0600.rs b/src/test/compile-fail/E0600.rs new file mode 100644 index 0000000000000..5457ff266086f --- /dev/null +++ b/src/test/compile-fail/E0600.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + !"a"; //~ ERROR E0600 +} diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr index 5e611d42a1491..43743b796d5e4 100644 --- a/src/test/ui/codemap_tests/issue-28308.stderr +++ b/src/test/ui/codemap_tests/issue-28308.stderr @@ -1,4 +1,4 @@ -error: cannot apply unary operator `!` to type `&'static str` +error[E0600]: cannot apply unary operator `!` to type `&'static str` --> $DIR/issue-28308.rs:12:5 | 12 | assert!("foo"); diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 889e3e01c6daa..f47791455afed 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,4 +1,4 @@ -error: cannot apply unary operator `!` to type `!` +error[E0600]: cannot apply unary operator `!` to type `!` --> $DIR/expr_unary.rs:18:16 | 18 | let x: ! = ! { return; 22 };