Skip to content

feat(types): function types as a third flavour (type: fn A, ...: R)#181

Merged
kollhof merged 1 commit into
mainfrom
fn-types
Jun 21, 2026
Merged

feat(types): function types as a third flavour (type: fn A, ...: R)#181
kollhof merged 1 commit into
mainfrom
fn-types

Conversation

@kollhof

@kollhof kollhof commented Jun 21, 2026

Copy link
Copy Markdown
Member

What

A fn A, ...: R in type position describes a function type -- a $FnType value, the third type flavour alongside $RecType/$TupleType. It is a sibling, not a subtype (a function is not a tuple), carrying the argument types ($params, a reverse-stored list) and the result type ($result).

This is the keystone for describing protocols in fink: a protocol is a record of named function types.

Behaviour

  • Declare: Foo = type: fn A, B: R. A sole fn body makes Foo the named function type directly (not a tuple wrapping it).
  • Compare: by identity via the existing deep_eq ref.eq fallback -- distinct declarations differ, aliases are equal. No new equality code.
  • Guard: a function type used as a match/bind guard is well-defined and runs, but matches nothing yet (instances are unconstructable, so a plain closure is not an instance and falls through).

How

  • types.wat: $FnType sibling struct; new_fn_type / fn_type_param / fn_type_result runtime funcs, accreted like the tuple family.
  • transform.rs: lower_type_expr mints a $FnType for a fn in type position; a sole-fn type body becomes the named fn type; three new BuiltIns thread the construction.
  • scopes/mod.rs: in type position a fn's params are type references, not binding sites -- resolved in the type scope rather than registered as param binds. (This is the one upstream-pass change; it fixes param type-names resolving to unbound.)
  • lower.rs / runtime_contract.rs / ir.rs / fmt.rs: emit + contract + CPS-pretty-print wiring for the new builtins.

Deferred (flagged in tests + comments)

  • Rendering a bare type value: repr_val / fmt_val have no $Type arm -- only values and instances render today, never type values themselves. Two repr tests pin the target output (Foo fn u8: u8) and are skip'd.
  • Typed-function instances: no type_apply $FnType arm. Constructing foo = Foo fn ...: ... (a closure tagged with its type, enabling runtime arg-checking on invocation) is a separate, larger increment touching $Closure and apply.

Tests

Full suite green (1366 lib, 0 failures), clippy clean, zero snapshot drift (no existing test declares a function type, so the new path adds no churn). New fn-type tests: equality, aliasing, guard-falls-through.

A `fn A, ...: R` in type position describes a function type -- a `$FnType`
value, sibling to `$RecType`/`$TupleType` (not a subtype: a function is
not a tuple). It carries the arg types (`$params`, reverse-stored list)
and the result type (`$result`), minted by accretion like the tuple
family: new_fn_type seeds it, fn_type_param cons-prepends each arg type,
fn_type_result sets the result.

`Foo = type: fn A: R` makes `Foo` the named function type directly (a
sole `fn` body is the type itself, not a tuple wrapping it). Function
types compare by identity via the existing deep_eq ref.eq fallback:
distinct declarations differ, aliases are equal. As a match/bind guard a
function type is well-defined and runs, but matches nothing yet --
instances are unconstructable.

In type position a `fn`'s params are type REFERENCES, not binding sites
(as they are for a fn value), so the scopes pass resolves them as
references in the type scope rather than registering param binds.

Deferred: rendering a bare type value (repr_val/fmt_val have no $Type arm
-- only values and instances render today; two repr tests pin the target
and are skipped), and typed-function instances (no type_apply $FnType
arm).
@github-actions

Copy link
Copy Markdown

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

@kollhof kollhof merged commit afe828a into main Jun 21, 2026
14 checks passed
@kollhof kollhof deleted the fn-types branch June 21, 2026 18:25
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