fix(check): a Math.* call has the type the emitter gives it
Math.max, Math.sqrt and the rest (and the bare min/max/abs/clamp) are computed inline by the
emitter, and L4 gave each the unknown type, which agrees with everything: Maroon Lake's trail
put Math.max(5, n) into Notify's string field a1 and it failed in LLVM ("%t63 defined with type
i32 but expected ptr"). It was never about two dispatches on a line - one is enough. The checker
now mirrors the emitter: a float/double first argument gives that type (sign an int); otherwise
min/max/abs/clamp keep the first argument's type, sign/floor/ceil/round/posmod/wrap/ping_pong are
ints, the rest fixed. Named arguments or an argument it cannot type leave it unknown.
rejected/math_into_text is the case. Reseeded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e6729b3123
commit
8e113f749a
6 changed files with 13780 additions and 12630 deletions
|
|
@ -178,6 +178,7 @@ function ck_call(e: Node) -> pointer {
|
|||
if b.kind == E_ID and ck_local(b.s) < 0 and ck_global(b.s) == null {
|
||||
# an alias (L6) is its target, labels and all, so its arguments are checked in full
|
||||
if (b.s == "Memory") { ck_raw(e, `Memory.{c.s}`) }
|
||||
if (b.s == "Math") and is_math_ns(c.s) { return ck_math(e, c.s) }
|
||||
let al = ns_alias_find(b.s, c.s)
|
||||
if al >= 0 {
|
||||
var tf = ck_fn(g_al_target[al])
|
||||
|
|
@ -250,9 +251,47 @@ function ck_call_named(e: Node, name: pointer) -> pointer {
|
|||
mg_ref(e.a, g) # 0.S2: a call through a var of a function type reads it
|
||||
return ck_call_sig(e, name, g.ty)
|
||||
}
|
||||
if is_math_builtin(name) { return ck_math(e, name) }
|
||||
ck_walk_args(e)
|
||||
return "?"
|
||||
}
|
||||
# Math.max(a, b), bare max(a, b): the emitter computes these inline, and their type is the one it
|
||||
# gives them - a float or double argument first is that type (sign an int), else the fixed-point
|
||||
# path: min, max, abs and clamp keep the first argument's type, the rounding and wrapping ones an
|
||||
# int, the rest a fixed. Left "?", a Math.max(5, n) went into a string field and failed in LLVM.
|
||||
function ck_math(e: Node, meth: pointer) -> pointer {
|
||||
if len(e.kids) == 0 or e.kids[0].kind == E_FINIT {
|
||||
ck_walk_args(e)
|
||||
return "?"
|
||||
}
|
||||
let tys = new []pointer
|
||||
var i = 0
|
||||
while i < len(e.kids) {
|
||||
push(tys, ck_expr(e.kids[i]))
|
||||
i += 1
|
||||
}
|
||||
if ck_unknown(tys[0]) { return "?" }
|
||||
if ck_is_float(tys[0]) {
|
||||
if (meth == "sign") { return "int" }
|
||||
var t = tys[0]
|
||||
i = 1
|
||||
while i < len(tys) {
|
||||
if (tys[i] == "double") { t = "double" }
|
||||
i += 1
|
||||
}
|
||||
return t
|
||||
}
|
||||
# a later float argument moves the emitter onto the float path only when it can see it
|
||||
i = 1
|
||||
while i < len(tys) {
|
||||
if ck_unknown(tys[i]) or ck_is_float(tys[i]) { return "?" }
|
||||
i += 1
|
||||
}
|
||||
if (meth == "min") or (meth == "max") or (meth == "abs") or (meth == "clamp") { return tys[0] }
|
||||
if (meth == "sign") or (meth == "floor") or (meth == "ceil") or (meth == "round") { return "int" }
|
||||
if (meth == "posmod") or (meth == "wrap") or (meth == "ping_pong") { return "int" }
|
||||
return "fixed"
|
||||
}
|
||||
# emit E(field: v): each field gets the type the event declares for it
|
||||
function ck_emit(s: Node) -> void {
|
||||
let ev = find_event(s.s)
|
||||
|
|
|
|||
13172
selfhost/ludicc.seed.ll
13172
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue