soma.cell

E0022: invariant_issue

E0022 invariant_issue — a memory invariant is malformed or names something it cannot read.

A compile-time error of soma check, the checker of the Soma programming language (soma explain E0022).

The rule

A memory invariant may only read the section's slot names, value, key, size and builtins. invariant balance >= 0 names nothing (the slot is balances), so soma check refuses it and suggests the slot name instead of letting a rule that could never be evaluated through. Fix the name so the invariant reads an existing slot.

A program that triggers it

wrong.cell

cell Accounts {
    face {
        signal credit(id: String, cents: Int) -> Int
    }
    memory {
        balances: Map<String, Int> [persistent]
        invariant balance >= 0
    }
    on credit(id: String, cents: Int) {
        let total = (balances.get(id) ?? 0) + cents
        balances.set(id, total)
        return total
    }
}

What soma check prints:

$ soma check wrong.cell
error: memory invariant references unknown name 'balance' (did you mean 'balances'?) — invariants may use the section's slot names, 'value', 'key', 'size', and builtins
  --> wrong.cell:7:9
  |
7 |         invariant balance >= 0
  |         ^
  = code: E0022
✗ 1 error(s), 0 warning(s).

The fix field of soma check --json: memory invariant references unknown name 'balance' (did you mean 'balances'?) — invariants may use the section's slot names, 'value', 'key', 'size', and builtins

On line 7, invariant balance >= 0 becomes invariant balances >= 0.

wrong.cell → right.cell

--- wrong.cell
+++ right.cell
@@ -5,5 +5,5 @@
     memory {
         balances: Map<String, Int> [persistent]
-        invariant balance >= 0
+        invariant balances >= 0
     }
     on credit(id: String, cents: Int) {

With the fix, soma check accepts the program:

$ soma check right.cell
✓ All checks passed.