Repository navigation
🐛 fix: Let judge, expect and refuse run outside meow test - #159
Conversation
Closes #151 `judge`, `expect` and `refuse` compiled to `meow_testing.Judge(...)` in a file that never imported the package, so `meow run` and `meow build` answered with raw Go — `undefined: meow_testing`, naming no line of the .nyan file — while `meow test` worked. The checker accepted them everywhere and the interpreter ran them everywhere, so the CLI was the odd one out. They work anywhere now. An assertion that holds answers with catnap; one that fails answers with a Furball carrying its message, which `~>` can catch: nya(judge(1 == 1, "one is one")) # => catnap nya(judge(1 == 2, "nope") ~> "caught") # => caught Option 1 of the two the issue sets out. Option 2, refusing them outside a test file, would have refused them in the playground too, which has no test mode — undoing #140, which implemented them there so the tutorial's section on testing runs when pasted in. Why. ensureImport registered the package but never marked it used, and usedImports keeps only what was marked — the right rule for a `nab` import, which a program may ask for and never call into, and the wrong one for a package the generator itself is about to emit a selector into. Only the test wrapper named "testing" as used, by hand, which is why `meow test` worked. ensureImport marks it now. seed, from the issue's related note: codegen answered a seed call with a catnap and spliced its arguments into nothing, so `seed(nya("x"))` printed nothing compiled and `x` in the playground. It goes through a runtime `meow.Seed` now, which is also what the interpreter calls, so the two agree by construction — including on an argument that failed, which Seed passes on the way nya does. The first version of this fix answered catnap in the interpreter and passed the Furball on in codegen; the golden caught it. `meow test -fuzz` still reads seed calls out of a target's body before it is generated, so a corpus is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Scc7p1RecmFoikhcXwnTMu
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (9)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe change updates generated imports and assertion documentation, adds a runtime ChangesAssertion builtins
Seed argument handling
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix · Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to No concrete issue currently blocks merging. The generated seed result path remains unverified, so normal checks should still be completed. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Assertions can now run in ordinary compiled programs, and seed arguments now run consistently across execution modes. The reviewed paths do not show a new privileged capability or a confirmed security finding, but deployment-level controls were not available to verify. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. A rabbit checks assertions in the grass, Comment |
…164) ## Overview Closes #163 A failure inside a lambda was reported, by the compiled program, at the line that *called* the lambda. A lambda passed to `lick` was blamed on the whole call: ```meow nyan xs = [1, 2] nya(lick(xs, paw(x) { bring to_float("bad") })) ``` ``` prog.nyan:2:1: Hiss! Cannot read "bad" as a Float, nya~ # before, compiled prog.nyan:3:3: Hiss! Cannot read "bad" as a Float, nya~ # after, and the playground always ``` ### Why The generated body already recorded the failing line. It then handed its result back through `meow.Returning(__caller, v)`, which always put the program back at the caller's position. Its doc comment assumed "a call that fails never reaches it". That holds where a failure panics (a typed function). A boxed body, though, hands its failure back as a value, an unhandled Furball, and that goes through `Returning` like any result. So it was not only lambdas: any function whose result is boxed, such as `meow f() P` returning a kitty, had its failure moved onto the calling line. ### The change `Returning` now follows the rule `meow.Call` already keeps: it goes back to the caller only when the value is not an unhandled Furball. The change is one runtime function. No generated code changes, so no golden moves. A lambda that succeeds, or one that caught its own failure with `~>`, still leaves the program at the call site. A failure later in the same statement is still blamed on that statement, and both cases are pinned. ## Verification - [x] `go test ./...` passes - [x] `go vet ./...` passes - [x] Golden files updated if needed: none moved - [x] New `compiler/lambda_position_test.go` runs 7 programs on **both** the compiled binary and the interpreter. It requires the same output and the same failure, position included. Cases: a lambda called by name, a lambda passed to `lick`, the last line of a longer lambda, a lambda called inside a typed function, a named function returning a kitty, a failure after a lambda that succeeded, and a failure after a lambda that caught its own. The five failure cases fail on the compiled side without the fix; the two success cases pass either way. - [x] New `runtime/meowrt/position_test.go` unit tests for `Returning`: it goes back to the caller for a boxed and for a native result, stays put for an unhandled Furball, and goes back for a caught one. The Furball case fails without the fix. - [x] WASM playground builds. `gofmt -l` is clean, and staticcheck, gocritic and misspell are clean on the changed files. - [x] The e2e examples (`hello`, `fibonacci`, `fizzbuzz`, `list_ops`) run ## Impact - [ ] Compiler (lexer / parser / checker / codegen) - [x] Runtime (meowrt / file / http): `Returning` in `runtime/meowrt/position.go` - [ ] CLI - [ ] Documentation - [ ] Playground: unchanged, it already reported the line that failed A `meow` binary run outside this checkout builds against the published runtime module, so it picks this up with the next release that carries the runtime, as it did for `Seed` in #159. ## AI Session - Session URL: https://claude.ai/code/session_01Scc7p1RecmFoikhcXwnTMu ## Checklist - [x] I have read the [CONTRIBUTING guide](../CONTRIBUTING.md) - [x] My changes follow the project's coding style - [x] I have added/updated tests for my changes - [x] Commit messages use [gitmoji](https://gitmoji.dev/) prefix 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Scc7p1RecmFoikhcXwnTMu --- _Generated by [Claude Code](https://claude.ai/code/session_01Scc7p1RecmFoikhcXwnTMu)_ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Failures inside lambdas are now reported at the line where they occur, rather than at the caller’s line. * When a lambda handles its own failure, execution resumes with the caller’s position correctly restored. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude <noreply@anthropic.com>
Overview
Closes #151
judge,expectandrefusecompiled tomeow_testing.Judge(...)in a file that never imported the package, someow runandmeow buildanswered with raw Go —undefined: meow_testing, naming no line of the.nyanfile — whilemeow testworked. The checker accepted them everywhere and the interpreter ran them everywhere, so the CLI was the odd one out.They work anywhere now. An assertion that holds answers with
catnap; one that fails answers with aFurballcarrying its message, which~>can catch:Option 1 of the two the issue sets out. Option 2 — refusing them outside a test file — would have refused them in the playground as well, which has no test mode. That would undo #140, which implemented them in the interpreter precisely so that the tutorial's section on testing runs when a reader pastes it in.
What to look at
ensureImportregistered the package but never marked it used, andusedImportskeeps only what was marked. That is the right rule for anabimport — a program may ask for a package and never call into it, and Go refuses an unused import — and the wrong one for a package the generator itself is about to emit a selector into. EveryensureImportcall site is one of those. Only the test wrapper namedtestingas used, by hand, which is whymeow testworked andmeow rundid not.ensureImportmarks it now.seed, from the issue's related note. Codegen answered a seed call with a catnap and spliced its arguments into nothing, soseed(nya("x"))printed nothing compiled andxin the playground. It goes through a runtimemeow.Seednow, and the interpreter calls that same function, so the two agree by construction. That also removed the__seedplaceholderbuiltinvalue.gocarried so that namingseedas a value had something to wrap.meow.Seedpasses an unhandled Furball on, the waynyadoes, so a seed whose argument failed says so rather than answering catnap as if nothing had happened.meow test -fuzzis unchanged. It still reads seed calls out of a target's body before the body is generated, so a corpus is the same corpus. Run end to end onexamples/fuzz_arithmetic.nyan: 5 seeds gathered, then fuzzing for 10s, PASS.Caught on the way
The first version of the
seedfix answered catnap in the interpreter whilemeow.Seedpassed the Furball on in codegen —seed(judge(false, "x")) ~> "caught"printedcatnapin the playground andcaughtcompiled. A new divergence, introduced by the fix for an old one. The golden caught it once the case was written into it, and the interpreter now callsmeowrt.Seedrather than a catnap of its own.Verification
go test ./...passesgo vet ./...passestestdata/assertions_anywhere, read line by line. No existing golden moved.TestTheseGoldensPrintTheSameUnderTheInterpreter(generalised from the one-golden test ✨ feat: Let a binding take a builtin's name where it is called #158 added) holds the interpreter to bothbinding_shadows_builtinandassertions_anywhere, byte for bytegofmt -l .cleanmeow test examples/catwalk_example_test.nyanpasses;meow test -fuzz examples/fuzz_arithmetic.nyanpassesstaticcheck -checks 'all,-ST1005'(the repo's.golangci.ymlset) over the changed packages: every finding is on a line this diff does not touch, which is what--new-from-revreports onWritten test-first: the golden was red for the right reason — eight
undefined: meow_testinglines — beforeensureImportchanged, and red again on the interpreter side before itsseedchanged.One thing worth knowing if you reproduce this by hand: a
meowbinary run from outside the checkout pins the published runtime module rather than the working copy, so a locally built binary run from/tmpanswersundefined: meow.Seeduntil this is released. That is howbuildModContenthas always worked and it is what #152'smeow.BuiltinFuncwent through too; from inside the checkout, or with a released binary, the runtime matches the compiler.Impact
meowrt.Seeddocs/stdlib.mdand its website copypkg/interpreterThe stdlib docs still said the three assertions panic on failure, which has not been true since the panic-to-Furball migration, and listed them under
nab "testing"as if they needed one. Both are corrected, with a short note that they are builtins usable anywhere.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01Scc7p1RecmFoikhcXwnTMu
Generated by Claude Code
Summary by CodeRabbit
New Features
judge,expect, andrefuseare available as builtins, including outside tests. Successful assertions returncatnap; failures return a message that can be caught with~>.seednow evaluates its arguments and preserves the first unhandled failure.Bug Fixes
meow test.Documentation