Add (param :as type) annotations to all fn/lambda params across SX spec

Extend the type annotation system from defcomp-only to fn/lambda params:
- Infrastructure: sf-lambda, py/js-collect-params-loop, and bootstrap_py.py
  now recognize (name :as type) in param lists, extracting just the name
- bootstrap_py.py: add _extract_param_name() helper, fix _emit_for_each_stmt
- 521 type annotations across 22 .sx spec files (eval, types, adapters,
  transpilers, engine, orchestration, deps, signals, router, prove, etc.)
- Zero behavioral change: annotations are metadata for static analysis only
- All bootstrappers (Python, JS, G1) pass, 81/81 spec tests pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 20:27:36 +00:00
parent c82941d93c
commit b99e69d1bb
23 changed files with 532 additions and 498 deletions

View File

@@ -41,7 +41,7 @@
;; --------------------------------------------------------------------------
(define-async async-render
(fn (expr env ctx)
(fn (expr (env :as dict) ctx)
(case (type-of expr)
"nil" ""
"boolean" ""
@@ -57,7 +57,7 @@
(define-async async-render-list
(fn (expr env ctx)
(fn (expr (env :as dict) ctx)
(let ((head (first expr)))
(if (not (= (type-of head) "symbol"))
;; Non-symbol head — data list, render each item
@@ -139,7 +139,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-raw
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((parts (list)))
(for-each
(fn (arg)
@@ -158,7 +158,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-element
(fn (tag args env ctx)
(fn ((tag :as string) (args :as list) (env :as dict) ctx)
(let ((attrs (dict))
(children (list)))
;; Parse keyword attrs and children
@@ -186,7 +186,7 @@
;; compiles inline for-each lambdas as for loops (which can contain await).
(define-async async-parse-element-args
(fn (args attrs children env ctx)
(fn ((args :as list) (attrs :as dict) (children :as list) (env :as dict) ctx)
(let ((skip false)
(i 0))
(for-each
@@ -211,7 +211,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-component
(fn (comp args env ctx)
(fn ((comp :as component) (args :as list) (env :as dict) ctx)
(let ((kwargs (dict))
(children (list)))
;; Parse keyword args and children
@@ -233,7 +233,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-island
(fn (island args env ctx)
(fn (island (args :as list) (env :as dict) ctx)
(let ((kwargs (dict))
(children (list)))
(async-parse-kw-args args kwargs children env ctx)
@@ -262,7 +262,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-lambda
(fn (f args env ctx)
(fn ((f :as lambda) (args :as list) (env :as dict) ctx)
(let ((local (env-merge (lambda-closure f) env)))
(for-each-indexed
(fn (i p) (env-set! local p (nth args i)))
@@ -275,7 +275,7 @@
;; --------------------------------------------------------------------------
(define-async async-parse-kw-args
(fn (args kwargs children env ctx)
(fn ((args :as list) (kwargs :as dict) (children :as list) (env :as dict) ctx)
(let ((skip false)
(i 0))
(for-each
@@ -301,7 +301,7 @@
;; Bootstrapper emits this as: [await async_render(x, env, ctx) for x in exprs]
(define-async async-map-render
(fn (exprs env ctx)
(fn ((exprs :as list) (env :as dict) ctx)
(let ((results (list)))
(for-each
(fn (x) (append! results (async-render x env ctx)))
@@ -319,7 +319,7 @@
"map" "map-indexed" "filter" "for-each"))
(define async-render-form?
(fn (name)
(fn ((name :as string))
(contains? ASYNC_RENDER_FORMS name)))
@@ -331,7 +331,7 @@
;; and eval-cond from render.sx for correct scheme/clojure classification.
(define-async dispatch-async-render-form
(fn (name expr env ctx)
(fn ((name :as string) expr (env :as dict) ctx)
(cond
;; if
(= name "if")
@@ -407,7 +407,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-cond-scheme
(fn (clauses env ctx)
(fn ((clauses :as list) (env :as dict) ctx)
(if (empty? clauses)
""
(let ((clause (first clauses))
@@ -429,7 +429,7 @@
;; --------------------------------------------------------------------------
(define-async async-render-cond-clojure
(fn (clauses env ctx)
(fn ((clauses :as list) (env :as dict) ctx)
(if (< (len clauses) 2)
""
(let ((test (first clauses))
@@ -449,7 +449,7 @@
;; --------------------------------------------------------------------------
(define-async async-process-bindings
(fn (bindings env ctx)
(fn (bindings (env :as dict) ctx)
;; env-extend (not merge) — Env is not a dict subclass, so merge()
;; returns an empty dict, losing all parent scope bindings.
(let ((local (env-extend env)))
@@ -470,7 +470,7 @@
(define-async async-process-bindings-flat
(fn (bindings local ctx)
(fn ((bindings :as list) (local :as dict) ctx)
(let ((skip false)
(i 0))
(for-each
@@ -495,7 +495,7 @@
;; --------------------------------------------------------------------------
(define-async async-map-fn-render
(fn (f coll env ctx)
(fn (f (coll :as list) (env :as dict) ctx)
(let ((results (list)))
(for-each
(fn (item)
@@ -512,7 +512,7 @@
;; --------------------------------------------------------------------------
(define-async async-map-indexed-fn-render
(fn (f coll env ctx)
(fn (f (coll :as list) (env :as dict) ctx)
(let ((results (list))
(i 0))
(for-each
@@ -543,7 +543,7 @@
;; ==========================================================================
(define-async async-aser
(fn (expr env ctx)
(fn (expr (env :as dict) ctx)
(case (type-of expr)
"number" expr
"string" expr
@@ -573,7 +573,7 @@
(define-async async-aser-dict
(fn (expr env ctx)
(fn ((expr :as dict) (env :as dict) ctx)
(let ((result (dict)))
(for-each
(fn (key)
@@ -587,7 +587,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-list
(fn (expr env ctx)
(fn (expr (env :as dict) ctx)
(let ((head (first expr))
(args (rest expr)))
(if (not (= (type-of head) "symbol"))
@@ -666,7 +666,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-eval-call
(fn (head args env ctx)
(fn (head (args :as list) (env :as dict) ctx)
(let ((f (async-eval head env ctx))
(evaled-args (async-eval-args args env ctx)))
(cond
@@ -694,7 +694,7 @@
;; --------------------------------------------------------------------------
(define-async async-eval-args
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((results (list)))
(for-each
(fn (a) (append! results (async-eval a env ctx)))
@@ -707,7 +707,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-map-list
(fn (exprs env ctx)
(fn ((exprs :as list) (env :as dict) ctx)
(let ((results (list)))
(for-each
(fn (x) (append! results (async-aser x env ctx)))
@@ -720,7 +720,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-fragment
(fn (children env ctx)
(fn ((children :as list) (env :as dict) ctx)
(let ((parts (list)))
(for-each
(fn (c)
@@ -744,7 +744,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-component
(fn (comp args env ctx)
(fn ((comp :as component) (args :as list) (env :as dict) ctx)
(let ((kwargs (dict))
(children (list)))
(async-parse-aser-kw-args args kwargs children env ctx)
@@ -776,7 +776,7 @@
;; --------------------------------------------------------------------------
(define-async async-parse-aser-kw-args
(fn (args kwargs children env ctx)
(fn ((args :as list) (kwargs :as dict) (children :as list) (env :as dict) ctx)
(let ((skip false)
(i 0))
(for-each
@@ -801,7 +801,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-call
(fn (name args env ctx)
(fn ((name :as string) (args :as list) (env :as dict) ctx)
(let ((token (if (or (= name "svg") (= name "math"))
(svg-context-set! true)
nil))
@@ -859,7 +859,7 @@
(list "map" "map-indexed" "filter" "for-each"))
(define async-aser-form?
(fn (name)
(fn ((name :as string))
(or (contains? ASYNC_ASER_FORM_NAMES name)
(contains? ASYNC_ASER_HO_NAMES name))))
@@ -871,7 +871,7 @@
;; Uses cond-scheme? from eval.sx (the FIXED version with every? check).
(define-async dispatch-async-aser-form
(fn (name expr env ctx)
(fn ((name :as string) expr (env :as dict) ctx)
(let ((args (rest expr)))
(cond
;; if
@@ -1000,7 +1000,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-cond-scheme
(fn (clauses env ctx)
(fn ((clauses :as list) (env :as dict) ctx)
(if (empty? clauses)
nil
(let ((clause (first clauses))
@@ -1022,7 +1022,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-cond-clojure
(fn (clauses env ctx)
(fn ((clauses :as list) (env :as dict) ctx)
(if (< (len clauses) 2)
nil
(let ((test (first clauses))
@@ -1042,7 +1042,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-case-loop
(fn (match-val clauses env ctx)
(fn (match-val (clauses :as list) (env :as dict) ctx)
(if (< (len clauses) 2)
nil
(let ((test (first clauses))
@@ -1062,7 +1062,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-thread-first
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((result (async-eval (first args) env ctx)))
(for-each
(fn (form)
@@ -1082,7 +1082,7 @@
;; --------------------------------------------------------------------------
(define-async async-invoke-or-lambda
(fn (f args env ctx)
(fn (f (args :as list) (env :as dict) ctx)
(cond
(and (callable? f) (not (lambda? f)) (not (component? f)))
(let ((r (apply f args)))
@@ -1104,7 +1104,7 @@
;; --------------------------------------------------------------------------
(define-async async-aser-ho-map
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((f (async-eval (first args) env ctx))
(coll (async-eval (nth args 1) env ctx))
(results (list)))
@@ -1120,7 +1120,7 @@
(define-async async-aser-ho-map-indexed
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((f (async-eval (first args) env ctx))
(coll (async-eval (nth args 1) env ctx))
(results (list))
@@ -1139,7 +1139,7 @@
(define-async async-aser-ho-for-each
(fn (args env ctx)
(fn ((args :as list) (env :as dict) ctx)
(let ((f (async-eval (first args) env ctx))
(coll (async-eval (nth args 1) env ctx))
(results (list)))
@@ -1170,7 +1170,7 @@
;; (set-expand-components!) — enable component expansion context var
(define-async async-eval-slot-inner
(fn (expr env ctx)
(fn (expr (env :as dict) ctx)
;; NOTE: Uses statement-form let + set! to avoid expression-context
;; let (IIFE lambdas) which can't contain await in Python.
(let ((result nil))
@@ -1196,7 +1196,7 @@
(define-async async-maybe-expand-result
(fn (result env ctx)
(fn (result (env :as dict) ctx)
;; If the aser result is a component call string like "(~foo ...)",
;; re-parse and expand it. This handles indirect component references
;; (e.g. a let binding that evaluates to a component call).