Skip to content

refactor(analyser): type the literals in a generic body by the body alone ✂️ - #340

Merged
timfennis merged 2 commits into
feat/type-checkerfrom
feature/generic-body-literals
Nov 13, 2026
Merged

timfennis merged 2 commits into
feat/type-checkerfrom
feature/generic-body-literals

Conversation

@timfennis

Copy link
Copy Markdown
Owner

A number literal in a generic function's body that the function's parameters reached became an extra type parameter, which each call settled: fn pair(x) => [x, 1] made pair(2.5) [2.5, 1.0]. That needed its own machinery: literal type parameters with bounds in each scheme, per-instance literal types read by the compiler, and special Int rules for calls from an earlier REPL line and for function values. As a result the same code typed differently in a file and in the REPL. A review of the type checker found that no realistic program used it.

A generic body's literals are now decided by the body alone, before the function is generalised, with the same look-ahead as literals anywhere else. They're never type parameters, so a file and the REPL type a program the same way.

Behaviour changes:

  • fn fact(n) => if n < 2 { 1 } else { n * fact(n - 1) } called as fact(5.0) is an analysis error pointing into the body. Writing 1.0 makes it work for Ints and Floats alike.
  • fn pair(x) => [x, 1] only takes Ints, fn k(x) => [x, "b"] only Strings, and fn f(xs) { xs.push(1); xs } only List<Int>.
  • fn inc(x) => x + 1 still takes Floats, since +(Float, Int) exists, and fib(10.0) still works. A literal at the call still adapts: let r: Float = g(3) makes the 3 a Float.
  • Next to fn f(xs: List<Any>), fn f(x) => f([x]) now makes x an Any, so it calls the List<Any> overload instead of reporting growing recursion.

Removed: Scheme.literals and literal_nodes, LiteralBounds, instantiate_literals, resolve_bounds, with_literals_named, literals_tied_to_parameters, number_literals, the Int rules for earlier batches and function values, the per-instance literal_types in the analysis, layout and compiler, and the bound de-duplication only copied literals needed (−353 lines of Rust).

A second commit sorts the unsettled literals by a key computed once, which was quadratic for a list of 20,000 values.

The manual's function and augmented-assignment pages are updated.

🤖 Generated with Claude Code

timfennis and others added 2 commits November 13, 2026 18:15
…lone ✂️

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-13T17:21:33.086594Z a9aa78a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@timfennis
timfennis merged commit 665b9c1 into feat/type-checker Nov 13, 2026
1 check passed
@timfennis
timfennis deleted the feature/generic-body-literals branch November 13, 2026 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant