fix inline issue

This commit is contained in:
2026-02-22 10:31:15 -06:00
parent b0ac5de7e2
commit d88692cd30
4 changed files with 74 additions and 11 deletions

View File

@@ -882,13 +882,43 @@ var mcode = function(ast) {
var inline_find = true
// --- Helper: emit arity-dispatched callback invocation ---
// ctx = {fn, fn_arity, result, null_s, frame, zero, one, az, ao, prefix}
// ctx = {fn, fn_arity, result, null_s, frame, zero, one, az, ao, prefix,
// known_arity (optional — compile-time arity of callback literal)}
// args = [slot_for_arg1, slot_for_arg2] — data args (not this)
// max_args = 1 or 2 — how many data args to support
var emit_arity_call = function(ctx, args, max_args) {
var call_one = gen_label(ctx.prefix + "_c1")
var call_two = gen_label(ctx.prefix + "_c2")
var call_done = gen_label(ctx.prefix + "_cd")
var call_one = null
var call_two = null
var call_done = null
var ka = ctx.known_arity
// When callback arity is known at compile time, emit only the matching
// call path. This avoids dead branches where parameters are nulled,
// which confuse the type checker after inlining (e.g. push on null).
if (ka != null) {
if (ka >= max_args) {
ka = max_args
}
if (ka == 0) {
emit_3("frame", ctx.frame, ctx.fn, 0)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_2("invoke", ctx.frame, ctx.result)
} else if (ka == 1 || max_args < 2) {
emit_3("frame", ctx.frame, ctx.fn, 1)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_3("setarg", ctx.frame, 1, args[0])
emit_2("invoke", ctx.frame, ctx.result)
} else {
emit_3("frame", ctx.frame, ctx.fn, 2)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_3("setarg", ctx.frame, 1, args[0])
emit_3("setarg", ctx.frame, 2, args[1])
emit_2("invoke", ctx.frame, ctx.result)
}
return null
}
call_one = gen_label(ctx.prefix + "_c1")
call_two = gen_label(ctx.prefix + "_c2")
call_done = gen_label(ctx.prefix + "_cd")
emit_3("eq", ctx.az, ctx.fn_arity, ctx.zero)
emit_jump_cond("jump_false", ctx.az, call_one)
emit_3("frame", ctx.frame, ctx.fn, 0)
@@ -952,7 +982,7 @@ var mcode = function(ast) {
}
// --- Helper: emit a reduce loop body ---
// r = {acc, i, arr, fn, len, fn_arity}; emits loop updating acc in-place.
// r = {acc, i, arr, fn, len, fn_arity, known_arity}; emits loop updating acc in-place.
// Caller must emit the done_label after calling this.
var emit_reduce_loop = function(r, forward, done_label) {
var acc = r.acc
@@ -971,7 +1001,8 @@ var mcode = function(ast) {
var f = alloc_slot()
var loop_label = gen_label("reduce_loop")
var ctx = {fn: fn_slot, fn_arity: fn_arity, result: acc, null_s: null_s,
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "reduce"}
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "reduce",
known_arity: r.known_arity}
emit_2("int", one, 1)
emit_2("int", zero, 0)
emit_1("null", null_s)
@@ -1428,7 +1459,8 @@ var mcode = function(ast) {
emit_2("length", fn_arity, fn_slot)
emit_2("int", zero, 0)
emit_2("int", one, 1)
r = {acc: acc, i: i, arr: arr_slot, fn: fn_slot, len: len, fn_arity: fn_arity}
r = {acc: acc, i: i, arr: arr_slot, fn: fn_slot, len: len, fn_arity: fn_arity,
known_arity: args.fn_known_arity}
if (nargs == 2) {
null_label = gen_label("reduce_null")
d1 = gen_label("reduce_d1")
@@ -1877,6 +1909,8 @@ var mcode = function(ast) {
var guard_t = 0
var guard_err = null
var guard_done = null
var cb_known = null
var cb_p = null
if (expr == null) {
return -1
@@ -2184,7 +2218,14 @@ var mcode = function(ast) {
a2 = nargs >= 3 ? gen_expr(args_list[2], -1) : -1
a3 = nargs >= 4 ? gen_expr(args_list[3], -1) : -1
d = alloc_slot()
return expand_inline_reduce(d, {arr: a0, fn: a1, init: a2, rev: a3}, nargs)
cb_known = null
if (args_list[1].kind == "function") {
cb_p = args_list[1].list
if (cb_p == null) cb_p = args_list[1].parameters
cb_known = cb_p != null ? length(cb_p) : 0
}
return expand_inline_reduce(d, {arr: a0, fn: a1, init: a2, rev: a3,
fn_known_arity: cb_known}, nargs)
}
// array(arr, fn) → inline map expansion
// Skip when first arg is a number literal (that's array(N, fn) — creation, not map)