implies is a word this compiler has never heard, and 82 assertions are silently truncated at the antecedent
$ grep -c 'implies\|==>' bootstrap/src/compiler.rs
0
$ grep -rn --include='*.t27' 'implies' specs/ | wc -l
82 (in 19 specs)
The corpus writes implication 82 times. The compiler contains no token, no
parse arm and no lowering for it, in any spelling.
What happens instead
Minimal probe, four lines, written from scratch:
invariant a_implies_b
given x = a()
assert x == true implies b() == false
$ t27c gen-c /tmp/imp.t27
void invariant_a_implies_b(void) {
__auto_type x = a();
assert((x == true)); <-- the consequent is gone
}
$ t27c check /tmp/imp.t27
Typecheck OK (0 errors, 0 warnings)
Real corpus site, specs/fpga/top_level.t27:201:
assert busy == false implies ready == true
/* gen-c */ assert((busy == false));
/* gen */ const ready = system_ready();
_ = ready; // dead after const-inlining
if (!(busy == false)) __t27_assert_fail(...);
// invariant: ... NOT CHECKED -- body was not lowered (T43)
Why this is worse than dropping the assertion
P implies Q is vacuously true whenever P is false. What is emitted is
assert P -- a different and strictly stronger proposition. The invariant
above says nothing when the system is busy; the generated code demands it
not be busy. An assertion that says nothing is a gap; an assertion that says
something else can fail on correct behaviour, or pass while the property it was
written for is violated.
Zig's output is the honest half of the same confusion: it emits the wrong check
AND, two lines later, NOT CHECKED -- body was not lowered. Two contradictory
statements about one invariant, in adjacent lines.
Not Verilog-only
This is C, Zig and Rust. The Verilog backend emits every invariant as a comment
(#2869), so it is the one backend where the truncation cannot mislead anybody --
the peer-backend oracle this project relies on has all three surviving arms
agreeing on the same wrong proposition, which is exactly the case #2847 named as
where cross-checking is blind.
The decision in it
Adding ==> as !a || b was already declined once, in #2774, for a stated
reason: a false antecedent then makes the invariant a pass, and what a quantified
implication means at codegen commits four backends. That reason still holds and
this issue does not reopen it.
What is not a decision: the silence. Whatever implies should mean, the
compiler should not accept the word, discard half the assertion, and print
Typecheck OK. The narrow repair is to reject it by name until it has a
meaning -- the third state this repository already has a word for.
Refs #2774, #2869
impliesis a word this compiler has never heard, and 82 assertions are silently truncated at the antecedentThe corpus writes implication 82 times. The compiler contains no token, no
parse arm and no lowering for it, in any spelling.
What happens instead
Minimal probe, four lines, written from scratch:
Real corpus site,
specs/fpga/top_level.t27:201:Why this is worse than dropping the assertion
P implies Qis vacuously true wheneverPis false. What is emitted isassert P-- a different and strictly stronger proposition. The invariantabove says nothing when the system is busy; the generated code demands it
not be busy. An assertion that says nothing is a gap; an assertion that says
something else can fail on correct behaviour, or pass while the property it was
written for is violated.
Zig's output is the honest half of the same confusion: it emits the wrong check
AND, two lines later,
NOT CHECKED -- body was not lowered. Two contradictorystatements about one invariant, in adjacent lines.
Not Verilog-only
This is C, Zig and Rust. The Verilog backend emits every invariant as a comment
(#2869), so it is the one backend where the truncation cannot mislead anybody --
the peer-backend oracle this project relies on has all three surviving arms
agreeing on the same wrong proposition, which is exactly the case #2847 named as
where cross-checking is blind.
The decision in it
Adding
==>as!a || bwas already declined once, in #2774, for a statedreason: a false antecedent then makes the invariant a pass, and what a quantified
implication means at codegen commits four backends. That reason still holds and
this issue does not reopen it.
What is not a decision: the silence. Whatever
impliesshould mean, thecompiler should not accept the word, discard half the assertion, and print
Typecheck OK. The narrow repair is to reject it by name until it has ameaning -- the third state this repository already has a word for.
Refs #2774, #2869