cli: restore documented auto-run for main and inline programs#307
Merged
Conversation
Inline-lambda lifting emits synthetic top-level decls named __lit_N. These are an implementation detail of HOF dispatch and were leaking into the auto-run / multi-fn-listing logic, surfacing in the friendly 'available functions' error and confusing several persona reports. Filter them out at the source: any Decl::Function whose name starts with __ is excluded from the func-name set the CLI uses to pick a default entry, list candidates, or match a positional arg.
SKILL.md has long documented that a multi-fn file with a function called `main` auto-runs main, matching the convention every persona reaches for first. The CLI default branch was instead erroring out with 'defines multiple functions, please specify one' on every multi-fn file, even when main was the obvious entry point. Fix the auto-run heuristic to pick main when it exists. Multi-fn files without a main keep the friendly listing as before.
`ilo 'f>n;42'` was silently dumping the AST to stdout with exit 0 instead of running f. For piped consumers this is soundness-class: valid-looking JSON output that is not the program result. SKILL.md has documented inline auto-run since 0.x. Auto-run when an inline snippet has a runnable entry: main if present, else the only user-defined fn. Zero-fn snippets (type and alias declarations only) and multi-fn snippets without a main keep the legacy AST-dump fallback, so the `ilo '<snippet>'` inspection shortcut from PR #178 still works for non-runnable shapes. The explicit --ast flag continues to AST-dump unconditionally.
Cover the documented behaviour from SKILL.md end-to-end: - multi-fn file with main auto-runs main - multi-fn file with explicit func arg overrides main - inline single fn auto-runs (was AST-dumping, soundness fix) - inline multi-fn with main auto-runs main - inline multi-fn without main still AST-dumps (PR #178 legacy) - inline zero-fn (comment-only) still AST-dumps - synthetic __lit_N decls hidden from the multi-fn listing Also adds examples/autorun-main.ilo so the engine harness exercises the main-as-default path across every backend (tree, VM, Cranelift) and so future agents have an in-context demonstration of the canonical shape.
Several tests used `ilo '<single-fn snippet>'` with no args as a parse-acceptance smoke test, relying on the implicit AST-dump path that triggered for inline single-fn input. Now that inline auto-runs, those snippets would fail arity at runtime instead of dumping the AST. Switch the affected tests to the explicit `--ast` form, which keeps the parse/verify-acceptance signal cleanly decoupled from runtime semantics. Files touched: tests/eval_inline.rs (6 tests), tests/regression_friendly_errors.rs (run_ok helper), tests/regression_p001_cascade.rs (run_ok helper), src/main.rs (3 dispatch unit tests in the embedded module). No behaviour change beyond the inline auto-run fix in the earlier commit, just test-shape catch-up.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
danieljohnmorris
added a commit
that referenced
this pull request
May 16, 2026
twelve fixes since 0.11.3, surfaced by rerun4 personas plus standing asks: srt-Cranelift TLS desync (#306), CLI auto-run restoration (#307), OP_LISTAPPEND O(n^2) JIT memory regression (#308), precedence-pair hint false-positive on parens (#309), prefix ?? accepts call expression (#310), += pure-shape docs (#311), bare-mutation silent no-op verifier warning ILO-T033 (#312), asin/acos/atan inverse trig builtins (#313), flat cross-engine (#314), cond{~v} discard hint multi-stmt false-positive (#315), rsrt fn xs key-fn overloads (#316), xs.(expr) paren-after-dot diagnostic hint (#317).
This was referenced May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two soundness-class regressions in the CLI default-engine dispatch:
ilo file.ilowithmain-as-default broken. A multi-fn file containingmainwas erroring withdefines multiple functions, please specify oneinstead of auto-runningmain. SKILL.md ([CLI invocation]) has documented this contract since 0.x.ilo 'f>n;42'silently AST-dumping. Inline programs with a runnable entry were dumping AST JSON to stdout with exit 0 instead of running. For piped consumers this is the worst kind of bug: valid-looking JSON output that is not the program result. SKILL.md: "Inline programs (ilo 'code') and single-function files run their entry function with the remaining CLI args; no explicit function name needed."Plus a related papercut several persona reports flagged: synthetic
__lit_Ninline-lambda decls were leaking into the "available functions" listing.The CLI default branch handled the single-fn-inline / multi-fn / main cases inconsistently with the documented contract, treating inline as "always AST-dump" and treating multi-fn files as "always error". This PR aligns the runtime with the docs and tightens the dispatcher to hide compiler-internal names.
Repro
Before:
After:
What's in the diff
Five discrete commits:
cli: hide synthetic __lit_N decls from func-name discovery— filterDecl::Functionwhose name starts with__at the source. Synthetic names from inline-lambda lifting (parser/mod.rs ~line 2863) no longer leak into the auto-run heuristic, the multi-fn listing, or CLI positional-arg matching.__is reserved for the compiler so the filter is safe and forward-compatible if more synthetic prefixes land.cli: prefer main when a multi-fn file omits the func arg— restore the documentedmain-as-default convention for multi-fn files. Multi-fn files withoutmainkeep the friendly listing.cli: auto-run inline programs with a runnable entry—ilo '<single fn>'andilo '<multi-fn with main>'now auto-run. Zero-fn (declaration-only / comment-only) and multi-fn-without-main inline snippets still AST-dump, preserving the inspection escape hatch from PR main: skip verify errors in inline AST-dump mode #178.--astremains the explicit form for any case where AST output is wanted regardless of shape.test: pin auto-run contract across file and inline paths— extendstests/regression_cli_default.rswith 7 new cross-cutting tests, addsexamples/autorun-main.iloso the engine harness exercises the main-as-default path across tree / VM / Cranelift, and so future agents have an in-context demonstration.test: migrate pre-existing inline-snippet tests to --ast— several tests ineval_inline.rs,regression_friendly_errors.rs,regression_p001_cascade.rs, andmain.rs's embedded test module used inline single-fn snippets with required params as parse-acceptance smoke tests, relying on the implicit AST-dump path. Switched to explicit--astso the parse-acceptance signal stays decoupled from runtime semantics.Test plan
cargo test --release --features cranelift— 5296 passed, 0 failed across 134 suitescargo fmt --checkcargo clippy --release --features cranelift --all-targets -- -D warningsmulti_fn_file_with_main_auto_runs_main,multi_fn_file_explicit_func_arg_overrides_main,inline_single_fn_auto_runs,inline_multi_fn_with_main_auto_runs_main,inline_multi_fn_without_main_still_dumps_ast,inline_zero_fn_still_dumps_ast,synthetic_lambda_decls_hidden_from_multi_fn_listingexamples/autorun-main.iloruns across every engine viatests/examples_engines.rs--astalways wins, comment-only inline AST-dumpsFollow-ups
None. SKILL.md was already correct; the bug was runtime drift from the documented contract.