fix(compiler): == / != on references is identity; only text compares by content
emit_bin_vals lowered every pointer-typed ==/!= to @lp_str_eq, so two distinct records compared their bytes up to the first zero byte. Content compare now needs both sides to be text (string, or the untyped pointer/ptr runtime code carries text in); other references use icmp eq ptr, and string vs a non-text reference is a compile error. Adds selfhost/tests/identity.ludic; both seeds regenerated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e010c2cecc
commit
1900f9ca80
7 changed files with 19750 additions and 19403 deletions
|
|
@ -161,19 +161,31 @@ function emit_bin(e: Node) -> Val {
|
|||
return r
|
||||
}
|
||||
|
||||
# text types: `==` on two of these compares content, not the pointers. Besides
|
||||
# `string`, that is the untyped raw pointer — `pointer`, and `ptr`, the element of
|
||||
# a `pointers` buffer — which runtime code uses to carry text.
|
||||
function is_textish(t: pointer) -> bool { return (t == "string") or (t == "pointer") or (t == "ptr") }
|
||||
|
||||
# lower `a <op> b` on two already-evaluated operands. Shared by binary expressions
|
||||
# and compound assignment (`x += y` is exactly `x = x + y`), so both agree on
|
||||
# string concatenation, Q16.16 multiply/divide, and int->long promotion.
|
||||
# `isnull` marks a comparison against the literal null (pointer identity, not
|
||||
# string content).
|
||||
function emit_bin_vals(op: pointer, a: Val, b: Val, isnull: bool) -> Val {
|
||||
# strings are pointer-typed, so any `+` with a pointer operand is concatenation,
|
||||
# and `==`/`!=` between pointers is content comparison — except `x == null`,
|
||||
# which is a pointer-identity test and falls through to the icmp below.
|
||||
# strings are pointer-typed, so any `+` with a pointer operand is concatenation.
|
||||
# `==`/`!=` compares by content only when BOTH sides are text (`string`, or an
|
||||
# untyped raw pointer, see is_textish); every other reference — records,
|
||||
# slices, enums, buffers — compares by identity in the icmp below, as does
|
||||
# `x == null`. A string against a non-text reference is a type error.
|
||||
let ptrish = (llty(a.ty) == "ptr") or (llty(b.ty) == "ptr")
|
||||
if ptrish {
|
||||
if (op == ("+")) { return emit_str_op("+", a, b) }
|
||||
if ((op == ("==")) or (op == ("!="))) and not isnull { return emit_str_op(op, a, b) }
|
||||
if ((op == ("==")) or (op == ("!="))) and not isnull {
|
||||
if is_textish(a.ty) and is_textish(b.ty) { return emit_str_op(op, a, b) }
|
||||
if ((a.ty == "string") and (llty(b.ty) == "ptr")) or ((b.ty == "string") and (llty(a.ty) == "ptr")) {
|
||||
perr(`cannot compare {a.ty} with {b.ty} using {op}: strings compare by content, other references by identity`)
|
||||
}
|
||||
}
|
||||
}
|
||||
let fx = (a.ty == "fixed") or (b.ty == "fixed")
|
||||
# a 64-bit operand (and no fixed/ptr involved) promotes the whole expression to
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue