libs (panic | macros | test | assertions)
generic_assert
Make the assert!
macro recognize more expressions (utilizing the power of procedural macros), and extend the readability of debug dumps.
While clippy warns about assert!
usage that should be replaced by assert_eq!
, it's quite annoying to migrate around.
Unit test frameworks like Catch for C++ does cool message printing already by using macros.
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 expanded. The exact expanding rules should be determined when implemented, but an example is provided for reference.
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 a plain text fallback if the following conditions fail:
Debug
.std::ops
) and the type (may also be a reference) doesn't implement Copy
.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.
The new assert messages are likely to generate longer code, and it may be simplified for release builds (if benchmarks confirm the slowdown).
These examples are purely for reference. The implementor is free to change the rules.
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:
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:
let v = vec![0u8;1];
assert!(v.is_empty());
thread '<main>' panicked at 'assertion failed:
Expected: v.is_empty()'
With short-circuit:
assert!(true && false && true);
thread '<main>' panicked at 'assertion failed:
Expected: true && false && true
With expansion: true && false && (not evaluated)'
With bracket blocks:
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'
With fallback:
let a = NonDebug{};
let b = NonDebug{};
assert!(a == b);
thread '<main>' panicked at 'assertion failed:
Expected: a == b
With expansion: (a) == (b)'
assert!
.assert_{eq,ne}!
) as deprecated.macro_rules!
was considered, but the recursive macro can often reach the recursion limit.!=
to ==
) was considered, but this isn't suitable for all cases as not all types are total ordering.These questions should be settled during the implementation process.