soma.cell

E0024: guard_scope

E0024 guard_scope — a transition guard reads a name the calling handler does not bind.

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

The rule

A transition guard (a -> b { guard { amount <= 1000 } }) reads the locals of the handler that calls transition(), plus the cell's slots and _id / _from / _to. If a handler that transitions toward the guarded state does not bind every name the guard reads, the guard could not be evaluated, so soma check refuses it. Bind the name in that handler — here by taking amount as a parameter — or have the guard read a slot keyed by _id.

A program that triggers it

wrong.cell

cell Expenses {
    state claim {
        initial: submitted
        submitted -> approved { guard { amount <= 1000 } }
        submitted -> rejected
    }
    on approve_claim(id: String) {
        transition(id, "approved")
    }
    on reject(id: String) {
        transition(id, "rejected")
    }
}

What soma check prints:

$ soma check wrong.cell
error: guard on `submitted -> approved` reads 'amount', but handler `approve_claim` has no variable 'amount' — its transition() toward `approved` takes this edge whenever the instance is in `submitted` (which edge runs is decided at run time). A guard sees the locals of the handler calling transition(), the cell's memory slots, and _id / _from / _to: bind `let amount = …` before the call, or have the guard read a slot keyed by _id
  --> wrong.cell:4:41
  |
4 |         submitted -> approved { guard { amount <= 1000 } }
  |                                         ^
  = code: E0024
✗ 1 error(s), 0 warning(s).

The fix field of soma check --json: guard on `submitted -> approved` reads 'amount', but handler `approve_claim` has no variable 'amount' — its transition() toward `approved` takes this edge whenever the instance is in `submitted` (which edge runs is decided at run time). A guard sees the locals of the handler calling transition(), the cell's memory slots, and _id / _from / _to: bind `let amount = …` before the call, or have the guard read a slot keyed by _id

On line 7, on approve_claim(id: String) { becomes on approve_claim(id: String, amount: Int) {.

wrong.cell → right.cell

--- wrong.cell
+++ right.cell
@@ -5,5 +5,5 @@
         submitted -> rejected
     }
-    on approve_claim(id: String) {
+    on approve_claim(id: String, amount: Int) {
         transition(id, "approved")
     }

With the fix, soma check accepts the program:

$ soma check right.cell
✓ All checks passed.