76d61aeced
Lifts the monomorphic-only restriction. Lifted top-level fn now
becomes Forall(α..., Fn(t..., T...) -> tr) when the enclosing fn
is polymorphic; capture types may mention outer type vars and
the existing mono pipeline (Iter 12b/14a) specializes them
correctly at call sites.
- desugar.rs / lift.rs: scope-building unified — Forall fn-params
are now KnownType, not LetBound. Lift wraps augmented_ty in
Forall mirroring the enclosing fn.
- Name-as-value-in-in-term in a polymorphic enclosing fn is
rejected (eta-Lam wrap from 16b.5 has no Forall). Queued
separately as closure-conversion-with-polymorphism.
- examples/poly_rec_capture.{ailx,ail.json}: apply_n_times :
Forall(a). drives at Int and Bool to exercise two mono
instantiations.
- e2e + check + desugar tests: 116 → 120 (+4).
Codegen pipeline untouched — apply_subst_to_type substitutes
through Fn.params uniformly (original params + appended captures).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
58 lines
2.1 KiB
Plaintext
58 lines
2.1 KiB
Plaintext
; Iter 16b.6 — LetRec inside a polymorphic enclosing fn.
|
|
; `apply_n_times : Forall(a). Fn(Int, a, Fn(a) -> a) -> a`
|
|
; applies `f` to `x` exactly `n` times. The recursive helper `loop`
|
|
; captures `f` from the enclosing fn's params — `f`'s declared type
|
|
; is `Fn(a) -> a`, which mentions the outer fn's type var `a`. The
|
|
; 16b.6 lift produces a synthetic top-level fn
|
|
; `loop$lr_0 : Forall(a). Fn(Int, a, Fn(a) -> a) -> a`
|
|
; and rewrites `(app loop k acc)` → `(app loop$lr_0 k acc f)`.
|
|
;
|
|
; `main` drives `apply_n_times` at TWO distinct type instantiations
|
|
; so codegen's monomorphisation queue picks up `loop$lr_0` twice
|
|
; (once at `a = Int` to compute `succ` applied 5x to 0 → 5; once at
|
|
; `a = Bool` to compute `not` applied 4x to false → false). This
|
|
; exercises the substitution of the outer Forall.vars into both the
|
|
; original LetRec params and the appended capture types.
|
|
;
|
|
; Expected stdout (one per line): 5, false.
|
|
|
|
(module poly_rec_capture
|
|
|
|
(fn succ
|
|
(doc "Helper: increment Int. Used as the Fn(Int) -> Int instance.")
|
|
(type (fn-type (params (con Int)) (ret (con Int))))
|
|
(params x)
|
|
(body (app + x 1)))
|
|
|
|
(fn flip
|
|
(doc "Helper: boolean negation as a top-level fn (so it has an adapter for value-position).")
|
|
(type (fn-type (params (con Bool)) (ret (con Bool))))
|
|
(params b)
|
|
(body (app not b)))
|
|
|
|
(fn apply_n_times
|
|
(doc "Apply f to x exactly n times. Polymorphic in a.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con Int) a (fn-type (params a) (ret a)))
|
|
(ret a))))
|
|
(params n x f)
|
|
(body
|
|
(let-rec loop
|
|
(params k acc)
|
|
(type (fn-type (params (con Int) a) (ret a)))
|
|
(body
|
|
(if (app == k 0)
|
|
acc
|
|
(app loop (app - k 1) (app f acc))))
|
|
(in (app loop n x)))))
|
|
|
|
(fn main
|
|
(doc "Drive apply_n_times at Int (succ 5 times from 0) and Bool (not 4 times from false).")
|
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
|
(params)
|
|
(body
|
|
(seq (do io/print_int (app apply_n_times 5 0 succ))
|
|
(do io/print_bool (app apply_n_times 4 false flip))))))
|