Skip to content

Fix ===/any coercion bugs, in-operator crash, and add regression coverage#241

Merged
ASDAlexander77 merged 4 commits into
mainfrom
adv_tests
Jul 17, 2026
Merged

Fix ===/any coercion bugs, in-operator crash, and add regression coverage#241
ASDAlexander77 merged 4 commits into
mainfrom
adv_tests

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

  • Strict equality (===/!==) no longer coerces mismatched primitive kinds (1 === true was wrongly true); short-circuits to a constant when both operand types are unambiguous, differing primitives.
  • any == any / any != any now applies JS loose-equality coercion across differing boxed payload kinds (number↔string, boolean↔number, boolean↔string), instead of a raw byte-for-byte memcmp. Handles the fact that boxed integer literals carry concrete-width type tags (s32/s64) rather than "number".
  • CodeLogicHelper::conditionalExpressionLowering is now safe to call from within its own then/else builder callbacks (previously branched from stale block handles, corrupting control flow when nested — needed for the any-coercion fix's multi-way tag dispatch).
  • Fixed a stale test assertion in 01tuple.ts that relied on the old, buggy coercing === semantics.
  • Fixed an in-operator crash when the left-hand side is a string literal (e.g. "length" in arr) and a related literal-type field lookup bug.
  • Added regression coverage: 00bool_arith_ops.ts, 00mixed_type_ops.ts, 00in_method_names.ts, 00class_structural_extends.ts.
  • Documented (not fixed) a separate generator bug: manual .next() calls don't advance state on a const-bound generator (docs/bugs/00generator_manual_next.ts).

Test plan

  • Full test suite: 700/700 passing (ctest -C Debug)
  • Verified ===/!== no longer coerce across primitive kinds
  • Verified any==any/any!=any coercion in both directions for all three kind pairs, plus != and same-kind cases unaffected
  • Verified 01tuple.ts assertion matches actual coerced runtime value

🤖 Generated with Claude Code

ASDAlexander77 and others added 4 commits July 17, 2026 01:02
… tests

- mlirGenInLogic assumed any `in` expression whose right side has `.length`
  was a numeric-index check, so a string-literal left side (e.g. "length"
  in arr) got cast to an index type and crashed LLVM translation. Now
  falls through to the general field-lookup path for string literals.
- getFieldTypeByFieldName didn't strip LiteralType wrappers, so `in`
  checks against const strings/string literals (e.g. "length" in "hi")
  incorrectly resolved to false instead of using the underlying type's
  field lookup.
- Add 00in_method_names.ts and 00class_structural_extends.ts covering
  the #238 area (in-operator and structural extends against classes),
  wired into both test-compile and test-jit CMake targets. Verified
  against the full 696-test suite, no regressions.
- Document a separate, deferred bug in docs/bugs/: generators lose their
  state across manual .next() calls (only for...of works). Root-caused
  to const bindings lacking backing storage; a first fix attempt broke
  unrelated interface/symbol tests and was reverted, so the fix itself
  is left for a dedicated follow-up.
=== / !== previously shared codegen with ==/!=, so mismatched primitive
kinds (1 === true) were coerced to a common type and wrongly compared
equal. adjustTypesForBinaryOp now short-circuits to a constant when
both operand types are unambiguous, differing primitives.

AnyCompareOp's ==/!= lowering did a raw memcmp of the boxed payload
bytes, never applying JS loose-equality coercion across differing any
payload kinds (number<->string, boolean<->number, boolean<->string).
It now compares the boxed type tags first and coerces via the existing
cast helpers when they differ, accounting for the fact that boxed
integer literals carry concrete-width tags (s32/s64) rather than
"number".

Adds 00mixed_type_ops.ts covering cross-type binary op coercion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… assertion

conditionalExpressionLowering (CodeLogicHelper.h) branched into its result
block from the then/else block handles captured before invoking the
builder callbacks, assuming the insertion point never moved. That broke
as soon as a callback itself called the helper again (needed for
AnyCompareOp's new multi-way coercion dispatch), producing an "operation
with block successors must terminate its parent block" verifier error.
It now re-reads the actual insertion block after each builder runs, so
it composes safely when nested. AnyCompareOpLowering's local workaround
(nestableConditional) is removed in favor of the shared, now-fixed
helper.

01tuple.ts's `assert(obj8.field1 === 10)` relied on the old, buggy ===
semantics that coerced like == (fixed in the previous commit) -- field1
is string-typed and holds the coerced "10", so strict equality against
the number 10 is correctly false. Updated to match the coercion pattern
already used elsewhere in the same file.

Full suite: 700/700 passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 9e8d977 into main Jul 17, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the adv_tests branch July 17, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant