Skip to content

Commit

Permalink
Switch to custom Not trait instead of '!' operator
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed May 17, 2024
1 parent 79d1684 commit cbd91b8
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 43 deletions.
8 changes: 4 additions & 4 deletions src/ensure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,24 +815,24 @@ macro_rules! __fancy_ensure {
#[macro_export]
macro_rules! __fallback_ensure {
($cond:expr $(,)?) => {
if !$cond {
if $crate::__private::not($cond) {
return $crate::__private::Err($crate::Error::msg(
$crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`")
));
}
};
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($msg));
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($err));
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*));
}
};
Expand Down
28 changes: 28 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ pub fn Ok<T>(t: T) -> Result<T> {
// Not public API. Referenced by macro-generated code.
#[doc(hidden)]
pub mod __private {
use self::not::Bool;
use crate::Error;
use alloc::fmt;
use core::fmt::Arguments;
Expand Down Expand Up @@ -699,4 +700,31 @@ pub mod __private {
pub fn must_use(error: Error) -> Error {
error
}

#[doc(hidden)]
#[inline]
pub fn not(cond: impl Bool) -> bool {
cond.not()
}

mod not {
#[doc(hidden)]
pub trait Bool {
fn not(self) -> bool;
}

impl Bool for bool {
#[inline]
fn not(self) -> bool {
!self
}
}

impl Bool for &bool {
#[inline]
fn not(self) -> bool {
!*self
}
}
}
}
10 changes: 0 additions & 10 deletions tests/test_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use self::common::*;
use anyhow::{anyhow, ensure, Result};
use std::cell::Cell;
use std::future;
use std::ops::Not;

#[test]
fn test_messages() {
Expand Down Expand Up @@ -61,20 +60,11 @@ fn test_ensure_nonbool() -> Result<()> {
condition: bool,
}

impl Not for Struct {
type Output = bool;
fn not(self) -> Self::Output {
!self.condition
}
}

let s = Struct { condition: true };
match &s {
Struct { condition } => ensure!(condition), // &bool
}

ensure!(s);

Ok(())
}

Expand Down
14 changes: 13 additions & 1 deletion tests/ui/ensure-nonbool.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
use anyhow::{ensure, Result};
use std::ops::Deref;
use std::ops::{Deref, Not};

struct Bool(bool);

struct DerefBool(bool);

struct NotBool(bool);

impl Deref for DerefBool {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Not for NotBool {
type Output = bool;
fn not(self) -> Self::Output {
!self.0
}
}

fn main() -> Result<()> {
ensure!("...");

Expand All @@ -24,5 +33,8 @@ fn main() -> Result<()> {
ensure!(db);
ensure!(&db);

let nb = NotBool(true);
ensure!(nb);

Ok(())
}
106 changes: 78 additions & 28 deletions tests/ui/ensure-nonbool.stderr
Original file line number Diff line number Diff line change
@@ -1,41 +1,91 @@
error[E0600]: cannot apply unary operator `!` to type `&'static str`
--> tests/ui/ensure-nonbool.rs:16:5
error[E0277]: the trait bound `&str: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:25:13
|
16 | ensure!("...");
| ^^^^^^^^^^^^^^ cannot apply unary operator `!`
25 | ensure!("...");
| --------^^^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&str`
| required by a bound introduced by this call
|
= note: this error originates in the macro `$crate::__fallback_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`

error[E0600]: cannot apply unary operator `!` to type `&mut bool`
--> tests/ui/ensure-nonbool.rs:20:23
error[E0277]: the trait bound `&mut bool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:29:31
|
29 | Bool(cond) => ensure!(cond),
| --------^^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&mut bool`
| required by a bound introduced by this call
|
20 | Bool(cond) => ensure!(cond),
| ^^^^^^^^^^^^^ cannot apply unary operator `!`
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
= note: `__private::not::Bool` is implemented for `&bool`, but not for `&mut bool`
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
= note: this error originates in the macro `$crate::__fallback_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`

error[E0600]: cannot apply unary operator `!` to type `DerefBool`
--> tests/ui/ensure-nonbool.rs:24:5
error[E0277]: the trait bound `DerefBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:33:13
|
24 | ensure!(db);
| ^^^^^^^^^^^ cannot apply unary operator `!`
33 | ensure!(db);
| --------^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `DerefBool`
| required by a bound introduced by this call
|
note: an implementation of `Not` might be missing for `DerefBool`
--> tests/ui/ensure-nonbool.rs:6:1
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`

error[E0277]: the trait bound `&DerefBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:34:13
|
6 | struct DerefBool(bool);
| ^^^^^^^^^^^^^^^^ must implement `Not`
note: the trait `Not` must be implemented
--> $RUST/core/src/ops/bit.rs
34 | ensure!(&db);
| --------^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&DerefBool`
| required by a bound introduced by this call
|
| pub trait Not {
| ^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::__fallback_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`
help: consider dereferencing here
|
34 | ensure!(&*db);
| +

error[E0600]: cannot apply unary operator `!` to type `&DerefBool`
--> tests/ui/ensure-nonbool.rs:25:5
error[E0277]: the trait bound `NotBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:37:13
|
37 | ensure!(nb);
| --------^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `NotBool`
| required by a bound introduced by this call
|
25 | ensure!(&db);
| ^^^^^^^^^^^^ cannot apply unary operator `!`
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
= note: this error originates in the macro `$crate::__fallback_ensure` which comes from the expansion of the macro `ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`

0 comments on commit cbd91b8

Please sign in to comment.