-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add generic_assert #2011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add generic_assert #2011
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
- Feature Name: generic_assert | ||
- Start Date: 2017-05-24 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Make the `assert!` macro generic to all expressions, and extend the readability of debug dumps. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
While clippy warns about `assert!` usage that should be replaced by `assert_eq!`, it's quite annoying to migrating around. | ||
|
||
Unit test frameworks like [Catch](https://github.com/philsquared/Catch) for C++ does cool message printing already by using macros. | ||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
We're going to parse AST and break up them by operators (excluding `.` (dot, member access operator)). Function calls and bracket surrounded blocks are considered as one block and don't get split further. | ||
|
||
On assertion failure, the expression itself is stringified, and another line with intermediate values are printed out. The values should be printed with `Debug`, and compilation failure if not implemented (custom message should be used for that case). | ||
|
||
To make sure that there's no side effects involved (e.g. running `next()` twice on `Iterator`), each value should be stored as temporaries and dumped on assertion failure. | ||
|
||
## Examples | ||
|
||
```rust | ||
let a = 1; | ||
let b = 2; | ||
assert!(a == b); | ||
``` | ||
|
||
``` | ||
thread '<main>' panicked at 'assertion failed: | ||
Expected: a == b | ||
With expansion: 1 == 2' | ||
``` | ||
|
||
With addition operators: | ||
|
||
```rust | ||
let a = 1; | ||
let b = 1; | ||
let c = 3; | ||
assert!(a + b == c); | ||
``` | ||
|
||
``` | ||
thread '<main>' panicked at 'assertion failed: | ||
Expected: a + b == c | ||
With expansion: 1 + 1 == 3' | ||
``` | ||
|
||
Bool only: | ||
```rust | ||
let v = vec![0u8;1]; | ||
assert!(v.is_empty()); | ||
``` | ||
|
||
``` | ||
thread '<main>' panicked at 'assertion failed: | ||
Expected: v.is_empty()' | ||
``` | ||
|
||
With short-circuit: | ||
```rust | ||
assert!(true && false && true); | ||
``` | ||
|
||
``` | ||
thread '<main>' panicked at 'assertion failed: | ||
Expected: true && false && true | ||
With expansion: true && false && (not evaluated)' | ||
``` | ||
|
||
With bracket blocks: | ||
```rust | ||
let a = 1; | ||
let b = 1; | ||
let c = 3; | ||
assert!({a + b} == c); | ||
``` | ||
|
||
``` | ||
thread '<main>' panicked at 'assertion failed: | ||
Expected: {a + b} == c | ||
With expansion: 2 == 3' | ||
``` | ||
|
||
# How We Teach This | ||
[how-we-teach-this]: #how-we-teach-this | ||
|
||
- Port the documentation (and optionally compiler source) to use `assert!`. | ||
- Mark the old macros (`assert_{eq,ne}!`) as deprecated. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
- This will generate a wave of deprecation warnings, which will be some cost for users to migrate. However, this doesn't mean that this is backward-incompatible, as long as the deprecated macros aren't removed. | ||
- This has a potential performance degradation on complex expressions, due to creating more temporaries on stack (or register). | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
- Defining via `macro_rules!` was considered, but the recursive macro can often reach the recursion limit. | ||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
## Error messages | ||
- Should we use the negated version of operators (e.g. `!=` for eq) to explain the failure? | ||
- Should we dump the AST as a formatted one? | ||
- How are we going to handle multi-line expressions? | ||
|
||
## Operators | ||
- Should we handle non-comparison operators? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not. The negated operator may not be true for order operations if the type only implements
PartialOrd
. For example,f64::NaN < 5
andf64::NaN >= 5
are both false.