invalid_lemma: a @[lemma] that cannot be a theorem
A lemma is a function marked @[lemma]. Its result type, {Unit | P}, states a theorem P
about its parameters, and its body is the proof. A lemma never runs: the compiler removes every
lemma and every call to one before the program is built. So a lemma has to follow five rules,
numbered as in the message:
- L1. Its result type is
{Unit | P}, andPdoes not mention the unit value_. - L2. Its body is total and pure. It has no effects (
println,send,spawn), no failure path (panic,todo, a typed hole, a division the checker can’t prove safe), nomatchthat might not match, and no lambdas. It never binds a parameter’s name again, with aletor a pattern: the theorem is about the parameters as passed in, solet n = 0must not maken == 0look true. Anassertis allowed. Inside a lemma it is a step of the proof, checked statically, never at run time. - L3. It calls only reflected functions, other lemmas, constructors, and the builtins the
logic knows (arithmetic, comparisons on
IntandFloat,&&,||,not). - L4. If it is recursive, the checker can prove the recursion terminates. Its recursive call is used as the induction hypothesis.
- L5. It is only ever called, never used as a value. It carries none of
@[opaque],@[measure],@[diverges],@[trusted]or@[assume].
A program that triggers it
mod Main do
@[lemma]
fn bogus(n : Int) : {Unit | n == n + 1} do
panic("unreachable")
end
fn main() : Int do
0
end
end
bogus breaks L2. Its only path ends in panic, so on every path where it “returns”, anything
holds. Since a lemma never runs, nothing would ever catch the false theorem.
The fix
State something true, and prove it with a body that returns ():
mod Main do
@[lemma]
fn plus_zero(n : Int) : {Unit | n + 0 == n} do
()
end
fn main() : Int do
0
end
end
Why the rule exists
A lemma’s theorem becomes a fact at every call, with no runtime check behind it. Every rule closes one way to “prove” something false:
- a failure path proves anything on that path (L2);
- an effect would be lost when the call is removed (L2);
- an unknown callee has no definition to reason with (L3);
- an induction hypothesis over a recursion that may not terminate is circular (L4);
- a lemma used as a value would need to exist at run time (L5).
See also: the language reference, the lemmas guide, lemma_unproved, invalid_measure.
Scoped assert … by blocks use this diagnostic too. Their hints must be total and pure;
only a proved goal becomes a fact outside the block. See scoped proof hints.