semantic #17

Merged
crowmaki merged 2 commits from semantic into main 2026-08-25 17:35:20 +00:00
Owner
No description provided.
Pass 1 of semantic analysis (docs/semantics/30-collect.md). Walks the
program's items once, builds the DefTable, and resolves every written
type annotation to a Type. No body is entered and no expression is
typed; at the end of this pass the compiler knows what exists.

Phase: compile. Completes no fixture — the fixture driver stays red at
25 of 25, per .known-red — and unblocks the twenty-one that need a
table to resolve against.

- collect.rs: two sub-passes. `declare` mints a DefId for every declared
  name so a forward reference resolves; `lower` builds each Def against
  the complete set. Aliases expand at lowering (decision 6), and an
  expanded body is a template — every use site gets its placeholders
  renumbered, since a Type::Var is per-occurrence.
- The prelude seeds print, the array intrinsics, Span and Slice. A
  module that writes out a compiler-provided type *defines* it: the
  declaration replaces the seed in place and keeps its DefId, so the
  slice `slices.cat` declares is the one step 80 mints.
- Overload sets per qualified name, with the duplicate-signature check
  the spec's § Overload Resolution requires, including against the
  prelude's own members.
- hir.rs: the Def payloads step 20 deferred — type params, #[SOA],
  field privacy and defaults, enum variant values and base type,
  interface method signatures, and what tells an overload set from a
  rebound constant. Plus DefTable::describe_type, a source-shaped
  renderer, so no diagnostic prints the golden-test spelling of a type.

Bounded against two crashes reachable from ordinary source: lowering
depth (a nested alias chain overflowed the stack) and expanded alias
size (a branching chain doubled per level — 23 lines took 7.4 seconds).

Three adversarial review rounds; every finding either fixed or recorded
as a deferral in the step doc. 30-collect.md updated where the plan and
the implementation disagreed: the canonical union order, the real shape
of check_alias_cycles, and the prelude-seed rules.
Pass 2's skeleton (docs/semantics/40-bodies.md). A scope stack, name
resolution against it and the DefTable, statement lowering, and the
expressions whose type needs no inference. Inference proper is step 50;
this is the walk it plugs into.

Phase: compile. Completes volatile-types, const-types, struct-allocation,
switch, and the negatives no-default-value, type-name-collision,
switch-non-exhaustive, redeclaration. The driver stays red — check() is
still a stub until step 99 — so each was verified by driving collect and
lower_program directly.

- body.rs: BodyCtx per body, scopes that narrow, resolution in the order
  40-bodies.md fixes, and overload stages 1 and 2. Stage 3 is step 60,
  so two survivors are reported as ambiguous rather than picked.
- Overload resolution gained a stage 0: candidates are filtered by
  whether the call was written with a receiver, and the receiver is
  attached from the winner. Reading it off the first candidate made the
  emitted tree depend on declaration order, which the spec forbids.
- hir::Program carries the file's locals, so a file-scope statement that
  binds one no longer produces a LocalId indexing nothing.
- Three recursion bounds, each a property of what is being walked rather
  than of where the walk started: a byte budget over statement and
  expression frames, measured rather than guessed; and default_of
  returning its subtree's height, so a memoized answer cannot shorten a
  later one. Without that last one the same program was accepted or
  refused depending on declaration order.

Three spec gaps this step found were resolved in docs/prd/ first, as
AGENTS.md requires, and each carries its fixture:

- A C-style for header's initializer declares its binding, loop-scoped
  and widening as a `let`. The spec writes `for (i = 0; ...)` four times
  and never declares `i`. array-c-style-loop.cat promoted from parse/.
- switch is documented for the first time: arms typed against the
  scrutinee, enum and bool exhaustible, everything else needing a
  default, C-style fall-through, duplicate case values refused. It was
  in the grammar, the AST and the parser, and in no line of the spec.
- A name declared twice in one scope is an error, parameters included.

Fixtures: 25 -> 30 (22 positive, 8 negative). const-pointer.cat is added
red on purpose: § Type Modifiers' own timesTwo(@x) refusal was in no
fixture, so step 60 could have completed const-types.cat without ever
implementing the rule.

Two adversarial review rounds; 22 findings, all fixed or scheduled.
crowmaki deleted branch semantic 2026-08-25 17:35:20 +00:00
crowmaki referenced this pull request from a commit 2026-08-25 17:35:21 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
crowmaki/catlang!17
No description provided.