Skip to content

Commit 69a0d29

Browse files
proof(idris2): tighten Ephapax.IR.Decode to %default total (#96)
## Summary Sixth file in the `%default partial` → `%default total` chain. Companions: SExpr (#89), Stream (#90), Util (#91), Lexer (#93), AST (#94). Flip `%default partial → %default total`. Roughly 22 atomic encode/decode helpers (the `baseToAtom`/`atomToBase` style maps, `encodeLit`/`decodeLit`, `encodeTy`/`decodeTy`, `escape`/`unescape`, `encodeParam`/`decodeParam`, etc.) are now provably total under the file default. ## 7 `covering` markers retained Two distinct Idris2 0.8.0 limits force this: 1. **`encodeExpr` / `decodeExpr`** — structural recursion runs through `map encodeExpr es` and `traverse decodeExpr rest` for the `Block` case. The recursion *is* structural via list head/tail induction on a `List Expr`, but Idris2 SCT cannot trace the size decrease across the `Functor` / `Traversable` dictionary call. Same root cause as the existing `Show Expr` / `Eq Expr` `covering` markers in AST.idr (#94). 2. **`encodeDecl` / `decodeDecl` / `fromSExpr` / `toSExpr`** — transitively call the two above; inherit `covering`. 3. **`encode`** — `encode = show . toSExpr` depends on `Ephapax.IR.SExpr.show` totality, which lands in PR #89. After #89 merges, `encode` would still be `covering` from `toSExpr`. `covering` is strictly stronger than the previous file default of `partial` — no new escape. No `assert_total` / `believe_me`. ## Verification ``` $ IDRIS2_PREFIX=…/idris2/0.8.0 idris2 --check Ephapax/IR/Decode.idr 3/3: Building Ephapax.IR.Decode (Ephapax/IR/Decode.idr) $ idris2 --check Ephapax/Parse/Parser.idr # downstream 6/6: Building Ephapax.Parse.Parser $ idris2 --check Ephapax/Affine/Emit.idr # downstream 4/4: Building Ephapax.Affine.Emit ``` ## Refs - `#124` (proof-debt audit epic) - `#134` (ephapax totality sub-issue) - Companions: PR `#89` (SExpr), `#90` (Stream), `#91` (Util), `#93` (Lexer), `#94` (AST) ## Test plan - [x] `idris2 --check Ephapax/IR/Decode.idr` builds green under `%default total` - [x] Downstream Parse/Parser + Affine/Emit still build - [ ] CI green - [x] No `assert_*` / `believe_me`; only 7 deliberate `covering` markers (justified above) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 52079a7 commit 69a0d29

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

idris2/src/Ephapax/IR/Decode.idr

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Data.String
55
import Ephapax.IR.SExpr
66
import Ephapax.IR.AST
77

8-
%default partial
8+
%default total
99

1010
baseToAtom : BaseTy -> String
1111
baseToAtom Unit = "unit"
@@ -154,6 +154,7 @@ decodeTy (List [Atom "borrow", inner]) = pure (Borrow !(decodeTy inner))
154154
decodeTy (List [Atom "var", Atom v]) = pure (Var v)
155155
decodeTy _ = Left (Invalid "unknown type")
156156

157+
covering
157158
encodeExpr : Expr -> SExpr
158159
encodeExpr (Lit lit) = List [Atom "lit", encodeLit lit]
159160
encodeExpr (VarE name) = List [Atom "var", Atom name]
@@ -181,6 +182,7 @@ encodeExpr (Block es) = List (Atom "block" :: map encodeExpr es)
181182
encodeExpr (BinOpE op a b) = List [Atom "binop", Atom (binopToAtom op), encodeExpr a, encodeExpr b]
182183
encodeExpr (UnOpE op e) = List [Atom "unop", Atom (unaryToAtom op), encodeExpr e]
183184

185+
covering
184186
decodeExpr : SExpr -> Either ParseError Expr
185187
decodeExpr (List (Atom tag :: rest)) =
186188
case tag of
@@ -273,12 +275,14 @@ decodeParam (List [Atom name, ty]) = do
273275
pure (name, t)
274276
decodeParam _ = Left (Invalid "param must be (name ty)")
275277

278+
covering
276279
encodeDecl : Decl -> SExpr
277280
encodeDecl (Fn name params ret body) =
278281
List [Atom "fn", Atom name, List (map encodeParam params), encodeTy ret, encodeExpr body]
279282
encodeDecl (TypeDecl name ty) =
280283
List [Atom "type", Atom name, encodeTy ty]
281284

285+
covering
282286
decodeDecl : SExpr -> Either ParseError Decl
283287
decodeDecl (List (Atom "fn" :: Atom name :: List params :: ret :: body :: [])) = do
284288
ps <- traverse decodeParam params
@@ -291,17 +295,20 @@ decodeDecl (List (Atom "type" :: Atom name :: ty :: [])) = do
291295
decodeDecl _ = Left (Invalid "unknown decl")
292296

293297
public export
298+
covering
294299
fromSExpr : SExpr -> Either ParseError Module
295300
fromSExpr (List (Atom "module" :: Atom name :: List decls :: [])) = do
296301
ds <- traverse decodeDecl decls
297302
pure (MkModule name ds)
298303
fromSExpr _ = Left (Invalid "expected (module name (decls...))")
299304

300305
public export
306+
covering
301307
toSExpr : Module -> SExpr
302308
toSExpr (MkModule name decls) =
303309
List [Atom "module", Atom name, List (map encodeDecl decls)]
304310

305311
public export
312+
covering
306313
encode : Module -> String
307314
encode = show . toSExpr

0 commit comments

Comments
 (0)