Skip to content

Parse type/enum/union declaration syntax + scope resolution#177

Merged
kollhof merged 3 commits into
mainfrom
type-syntax
Jun 14, 2026
Merged

Parse type/enum/union declaration syntax + scope resolution#177
kollhof merged 3 commits into
mainfrom
type-syntax

Conversation

@kollhof

@kollhof kollhof commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary

Adds parsing and scope resolution for type / enum / union declaration syntax. This is the parser + name-resolution foundation that lets the VSCode extension (grammar / LSP) recognize type declarations without flagging declared names as unbound.

Parse-only at the AST/scopes level: no desugar/CPS/codegen semantics for type declarations yet (a declaration reaching CPS panics cleanly; no current path does). Downstream lowering — nominal identity, subtyping, construction, match-on-type — is future work.

What landed

Parser + AST (feat(ast)): three reserved keywords parsed into new NodeKind::Type / Enum / Union ({ params, sep, body }, mirroring Fn):

  • type: record (named fields), tuple (positional), unit (type _), generic (type T:)
  • enum T: closed-sum members (nullary + payload-carrying)
  • union: block of member types
  • ..Foo type-level spread (extension) in all three block bodies

Reuses existing parsers — record bodies are rec-literal arms, tuple/enum/union bodies are expr lists, spreads reuse parse_spread. Both source formatters, the partial-desugar transform, and the walker are wired.

Scopes (feat(scopes)): keyword-specific name resolution so the editor does not flag declared names as unbound:

  • type: — record field names are declarations (not resolved); field types, tuple positionals, and ..Foo resolve as type references.
  • union: — members resolve as references to existing types.
  • enum: — members mint constructors (the constructor name binds; payload types resolve against the generic params).
  • Type-declaration scopes are labelled by keyword ('type' / 'enum' / 'union') via a new ScopeKind::Type(kw).

Testing

Full suite green: 1345 lib + 42 CLI + 1 interop, 0 failed. New fixtures: test_types.fnk (9 AST tests) and test_scope_types.fnk (3 scope tests).

Follow-ups

  • Inline forms: A or B (inline union), union T1, T2, T3 (call form).
  • Usage-surface fixtures: construction (Foo {…} / Ni 1, 2 / Some 12), match-on-type patterns, member access / destructure (these reuse existing grammar but aren't yet pinned by tests).
  • Lowering: type-declaration semantics (nominal identity, subtyping, construction, match) — the substantive next increment.

kollhof added 3 commits June 14, 2026 17:23
Reserved keywords type/enum/union, parsed into new NodeKind::Type/Enum/
Union ({ params, sep, body }, mirroring Fn). Covers:
- type: record (named fields), tuple (positional), unit (type _), generic
  (type T:)
- enum T: closed-sum members (nullary + payload-carrying)
- union: block of member types
- ..Foo type-level spread (extension) in all three block bodies

Reuses existing parsers: record bodies are rec-literal arms (Arm ':'),
tuple/enum/union bodies are expr lists, spreads reuse parse_spread. Parse
+ AST + both source formatters + partial-desugar transform wired; CPS
panics (not yet lowered), scopes registers generic params + walks the
body, layout todo!. Parse-only: no type-decl semantics downstream yet.

New fixture test_types.fnk (9 tests).
Walk type-declaration bodies with keyword-specific name semantics so the
editor does not flag declared names as unbound:
- type:  record field names are declarations (not resolved); field types,
         tuple positionals, and ..Foo extensions resolve as type references.
- union: members resolve as references to existing types.
- enum:  members MINT constructors -- the constructor name binds, payload
         types resolve against the generic params.

Generic params bind in a child scope. New walk_type_member helper handles
the per-keyword member shapes. Fixture test_scope_types.fnk (3 tests).
Add ScopeKind::Type(kw) carrying the keyword so type/enum/union bodies
render as 'type'/'enum'/'union' rather than the misleading 'fn'. Behaves
like Fn for the non-module binding checks; only the display label differs.
@github-actions

Copy link
Copy Markdown

📦 This PR will release v0.86.0 (minor) when merged.

@kollhof kollhof merged commit 4850a2b into main Jun 14, 2026
14 checks passed
@kollhof kollhof deleted the type-syntax branch June 14, 2026 17:01
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