Skip to content

Add optional, droppable, and variadic-trailing parameters - #579

Open
LPTK wants to merge 75 commits into
hkust-taco:hkmc2from
LPTK:optional-params
Open

LPTK wants to merge 75 commits into
hkust-taco:hkmc2from
LPTK:optional-params

Conversation

@LPTK

@LPTK LPTK commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Description by Codex:


This adds optional and droppable parameters and allows required parameters after a variadic parameter, with support in function types, resolution, and JavaScript lowering.

  • Optional parameters: fun f(x, y?) and fun f(x, y?: T) allow callers to omit trailing arguments. Omitted arguments are undefined; an optional annotation includes undefined. Function types support both unnamed and named optional parameters.
  • Droppable parameters: drop marks arguments that callback implementations may ignore, including a droppable rest parameter. Prelude callback signatures now let functions such as Array.map accept callbacks that omit the index and array parameters.
  • Variadic parameters with a required suffix: fun f(x, y?, ...xs, z) assigns required arguments from both ends, fills optional leading positions from the remaining arguments, and collects the middle in xs.

Resolution checks obvious separate-signature and callback-layout mismatches (others will be reported by type the future checking pass), reports callback errors at their use sites, and retains parameter/result flows when approximating differing or compound signatures. Spread arguments are matched from both ends. Lowering extracts trailing parameters, preserves optionality through eta expansion and tail recursion, and avoids unsafe uncurrying. Runtime arity checks reject missing required arguments while allowing extra arguments to be ignored.

Non-tuple spreads now follow the JavaScript iteration protocol. @annotations.fresh identifies stable property keys, and @annotations.jsSymbol(path) associates a source member name with such a key in nominal and structural interfaces. Computed keys remain explicit operands through lowering and transformations, with access paths recovered across lexical scopes and imports. Resolution diagnoses key collisions, inconsistent overrides, and unavailable keys.

The prelude and iterable libraries adopt these features, including symbol-keyed iteration for arrays, strings, maps, and sets. Regression coverage includes callbacks, separate signatures, curried calls, spread layouts, generic element flows, keyed inheritance and imports, and bounded recursive inference growth. Optional parameters remain unsupported by the WebAssembly backend and InvalML.

- Syntax: `fun f(x, y?)`, `fun f(x, y?: T)`, `fun f(x, drop y)`, and in
  function types `(Int, Int?) -> R` and `(T, drop Int) -> R`.
- Optional parameters may be omitted by callers, in which case they are
  `undefined`; their annotated types therefore include `undefined`.
  Droppable parameters are always passed but may be ignored by
  implementations (e.g., the index and array passed by `Array#map`).
- Runtime arity checks now follow JavaScript: only missing arguments are
  reported, extra arguments are ignored. Callbacks with fewer parameters
  than their expected function type are accepted by the new resolver.
- Direct calls are checked statically against [required, positional].
- TailRecOpt resets omitted optional parameters; flow analysis, eta
  expansion and worker/wrapper account for optional parameters; Wasm
  rejects them.
- Prelude: Array/Map callbacks use `drop`, and the TODOs for optional
  parameters (Object, Number, String, Error, Array.from, Promise#then)
  are resolved.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
- The new resolver again rejects callbacks with fewer parameters than
  their expected function type, unless the omitted trailing parameters
  are marked `drop`. Callbacks also may not require arguments that
  callers may omit, and extra callback parameters must be optional.
- Remove the obsolete variance traverser of the elaborator, which only
  fed `TyParam.showDbg` and crashed on spreads in function types.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rest parameters may be marked `drop`, both in definitions
(`fun f(x, drop ...xs)`) and in function types
(`(Int, drop ...Array[Int]) -> Int`), in which case callbacks may omit
them. Function type rest parameters (`Spd` elements) now record whether
they are droppable.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
- `ParamList.restParam: Opt[Param]` becomes `variadic: Opt[Variadic]`,
  where `Variadic(param, trailing)` holds the (required) parameters
  following the variadic one, as in `fun f(x, ...xs, y)`. Function types
  support the same shape, as in `(Int, ...Array[Int], Str) -> R`.
- Arguments are assigned as in Ruby: required leading and trailing
  parameters take the first and last arguments, optional leading
  parameters take the remaining ones from left to right, and the
  variadic parameter takes the rest. Optional parameters cannot follow
  a variadic parameter, and there is at most one variadic parameter.
- Lowering desugars trailing parameters into a rest parameter and a
  prologue (`Lowering.lowerTrailingParams`), so passes running after it
  only see rest parameters (`ParamList.restParam` asserts this).
- The new resolver matches arguments to trailing parameters from the
  end, and only accepts callbacks with the same structure as their
  expected function type when trailing parameters are involved.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@LPTK LPTK changed the title Add optional and droppable parameters Add optional, droppable, and variadic-trailing parameters Oct 18, 2026
Comment thread hkmc2/shared/src/test/mlscript/interop/Arrays.mls Outdated
codex and others added 18 commits October 18, 2026 11:47
Join every compound-signature component at stable parameter endpoints and share conservative layout mapping with callbacks. Preserve element flows through rest slicing, keep later curried constraints connected, and document the distinction between lenient checking and flow preservation.
Observe Symbol.iterator, next, and result fields through stable per-spread
sites. Preserve known element flows alongside uncertainty and share synthesized
type-application interning between Array and Awaited.

Support symbol-keyed members in resolution, inheritance, and JavaScript output.
Compose alias argument polarity without discarding declaration variance or
explicit projections, and let lenient calls retain all known result flows.

Document the best-effort resolution policy and add protocol, ambiguity,
variance, and bounded-growth regressions. Include regenerated golden outputs.

Validation: ctest; hkmc2AllTests/test.
Declare annotations.jsSymbol in the prelude and recognize its resolved symbol.
Require a stable module/val path ending in a val marked annotations.fresh,
without checking Symbol types or attempting to prove freshness. Preserve key
identity across receiver aliases, require matching names and keys for overrides,
and carry runtime keys as explicit IR operands for reads, writes, and methods.

Interpret declared-module annotation identities before their values complete,
and publish completed overload sets without exposing a separate signature before
its implementation. Keep Iterator limited to next, make IteratorImpl iterable,
and expose native iterator results through Iterator & Iterable while preserving
all component flows.

Add runtime and diagnostic regressions, including an explicit FIXME for named
selection after a factory-local key escapes its lexical scope. Record the
requirement to confirm future language-design changes.

Validation: ctest and hkmc2AllTests/test passed. Include regenerated golden output.
@LPTK
LPTK marked this pull request as ready for review October 19, 2026 06:35
codex and others added 5 commits October 19, 2026 15:10
Pin, as :fixme, the issues found while reviewing optional, droppable,
and trailing parameters:
- Without inlining, Runtime.Tuple.getLeading returns () instead of
  undefined for omitted optional parameters before a variadic one.
- Stack-safe resumption drops rest parameters, which now also carry
  required trailing arguments.
- The Wasm backend crashes on trailing parameters.
- Legacy using-clause eta-expansion drops rest and trailing arguments.
- A user-defined ?: operator no longer parses.

Also cover the Wasm optional-parameter diagnostic and the legacy
separate-signature optionality check, which had no tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
codex and others added 13 commits October 21, 2026 18:22
Use the call layout matcher for tuple patterns, retain enclosing generic scopes when refining constructor patterns, and validate shared type interpretations once per erasure pass. Add diff-test regressions and document the outstanding Boolean expansion problem with a commented reproducer.
Preserve keyword-based this/super parsing together with optional source identifiers, and add integration coverage for grouped optional parameters and when splits.

Validation: ctest; focused diff tests; hkmc2AllTests/test.
codex and others added 14 commits October 22, 2026 20:35
Group callback and function-signature cases, fold small symbol, pattern, optional-value, and type-graph fixtures into their related suites, and remove redundant cases while retaining distinct resolver and backend coverage. Refresh all affected golden outputs.

Validation: ctest; hkmc2AllTests/test (1,119 tests passed).
Move the 23 new AI-authored diff-test files under mlscript/slop, including the upstream optional-binding regression suite, preserving their configuration and compilation fixtures. Add hkmc2SlopTests and sdtest, exclude the directory from main discovery, and retain aggregate validation.

Validation after rebasing onto 946a5b1: ctest; focused optional and variadic diff-tests; hkmc2AllTests/test (1,120 passed, including all 23 slop tests).
# Conflicts:
#	hkmc2/shared/src/main/scala/hkmc2/semantics/ups/SplitCompiler.scala
Share fixture compilation through a named SBT prerequisite so the Wasm and slop suites wait for the same task. This generates Wasm.mjs before slop tests run in a fresh checkout and avoids duplicate fixture compilation in aggregates.

Validation: hkmc2SlopTests/test with Wasm.mjs absent (23 slop tests passed); hkmc2AllTests/test (1,120 passed, one Wasm fixture compilation). Golden output unchanged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants