feat(lang): one call rule — bare literal list after 'of' is always an argument list (#405)#458
Merged
Merged
Conversation
…an argument list (#405) BREAKING. The compiler previously spread a bare literal arg list only at count > 1, so 'f of [x]' bound the whole 1-element list to the first parameter — an arity-dependent silent-wrong that broke 'fib of [n - 1]' the moment a defaulted param was added (#153). Now brackets after 'of' are an argument list at EVERY count ('f of []' zero args, 'f of [x]' one arg, 'f of [a, b]' two) and parentheses are one argument — 'f of ([x])' (#355) still passes a literal list whole. One rule, teachable in one sentence. - compiler.c: merge the zero-arg / count>1 branches into the universal arg-list rule (the whole change is the dropped count>1 guard). - lint: new W017 — bare 1-element literal arg list; names both unambiguous rewrites ('f of x' / 'f of ([x])'). Doubles as the migration audit: --lint over a repo surfaces every behavior-changed site. Flows to the LSP via the shared pass. - lib/eigen.eigs: the self-hosted interpreter's call binding now mirrors the C VM under the new rule (element-wise binding, 1-param pack-back for 2+ args, the #154 1-param empty-list bind), so meta parity holds by construction, not by accident. test_meta_parity pins both the new 1-element behavior and the #355 paren form. - tests: call-semantics rewritten as the spec-of-record (incl. the resurrected 'fib of [n - 1]' + defaulted-param regression); 13 list-intent sites across 10 test files parenthesized; W017 audit over lib/ + tests/ + examples/ is clean. - docs: SPEC call-conventions + COMPARISON rewritten (executable examples updated), DIAGNOSTICS W017 row, CLAUDE.md hard-won rule replaced, ROADMAP ticked. Gates: release suite 2568/2568; ASan+UBSan with detect_leaks=1 2568/2568, leak tally 0; make http + test_http_server.sh 32/32; freestanding 2-stage symbol gate OK. The ouroboros frontend.eigs parity leg deliberately rides the next release + pin bump (its differential runs against the pinned VM), with the chr raise and #411 tape headers. Closes #153 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| "list", name, name, name); | ||
| } | ||
|
|
||
| static void w017_scan(ASTNode *n, LintContext *ctx) { |
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.
Implements the #405 language change: a bare literal list after
ofis always an argument list, at every element count —f of []is zero arguments,f of [x]is one (the element, not the list),f of [a, b]is two. Parentheses remain the one-argument form:f of ([x])(#355) passes a literal list whole. This kills the arity-dependent silent-wrong wherefib of [n - 1]broke the moment a defaulted parameter was added.What's in the change
src/compiler.c: the whole semantic change is one droppedcount > 1guard — the zero-arg and multi-arg branches merge into the universal rule.f of x/f of ([x])). It doubles as the migration audit —--lintover a repo surfaces every behavior-changed call site.lib/eigen.eigs: the self-hosted interpreter's call binding rewritten to mirror the C VM under the new rule (element-wise binding, 1-param pack-back for 2+ args, Unflagged semantic change:g of []on a multi-param function now binds a=null (was a=[]) #154 empty-list bind), so meta parity holds by construction;test_meta_paritypins the new behavior and the paren form.tests/test_call_semantics.eigsrewritten as the spec-of-record, including the resurrectedfib of [n - 1]-with-default regression; 13 list-intent call sites across 10 test files migrated to the parenthesized form; repo-wide W017 audit clean.Gates run locally
detect_leaks=1: 2568/2568, leak tally 0make http+tests/test_http_server.sh: 32/32make freestanding-check: both stages OKEcosystem coordination
frontend.eigsparity leg deliberately rides the next release + pin bump (its differential gate runs against the pinned VM) together with thechrraise and Design: trace-tape format versioning — the tape is becoming a persisted artifact #411 tape headers;test/programs/call_convention.eigsstays pinned to v0.26.0 semantics until then.Closes #153
🤖 Generated with Claude Code