Skip to content

Fix llvm_unreachable aborts resolving unknown field/method names in getFieldTypeByFieldName - #238

Merged
ASDAlexander77 merged 3 commits into
mainfrom
fix/issue-231-array-field-unreachable
Jul 15, 2026
Merged

Fix llvm_unreachable aborts resolving unknown field/method names in getFieldTypeByFieldName#238
ASDAlexander77 merged 3 commits into
mainfrom
fix/issue-231-array-field-unreachable

Conversation

@ASDAlexander77

@ASDAlexander77 ASDAlexander77 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary

Crashes (commits 1-2)

  • Uint8Array/Int32Array resolve through the default lib as type Uint8Array = TypedArray<u8>, a generic class built on Array<T>. --export=all forces eager full-body instantiation of referenced types, which walks every method of Array<T>/TypedArray<T> -- including ones like push/pop/entries that call through to this.data.<method>(), an extension-method call on the raw array type.
  • getFieldTypeByFieldName had the same defect in five branches: it special-cased a couple of known field names, then called llvm_unreachable("not implemented") for anything else -- including legitimate method names -- instead of returning "not found" so the caller can keep looking (e.g. via extension functions). Fixed all five (ArrayType, ConstArrayType, StringType, InterfaceType, ClassType).
  • This also matters for the UnionType branch in the same function, which calls getFieldTypeByFieldName per member and expects a falsy result for "member doesn't have this field" -- before this fix, a union containing an affected member type would abort the whole process instead of just excluding that member.

Wrong lookup table (commit 3)

  • While reviewing the ClassType branch, found it called getInterfaceInfoByFullName() with a class's full name instead of getClassInfoByFullName() -- looking up class field/method info in the wrong registry. Since classes and interfaces are registered in separate tables, this essentially never succeeded for a real class, silently returning "field not found" for every field/method access on a class type. This affects the in operator on class instances and extendsType's structural matching of classes against tuple-shaped constraints (e.g. T extends { length: number }).
  • ClassInfo::findField/findMethod have a different signature than InterfaceInfo's (findField takes a bool& out-param and returns a value rather than a pointer), so the call site needed updating to match, not just the lookup function swap.

Test plan

  • Rebuilt tslang (release) with all three commits.
  • Compiled the reporter's native.d.ts (from the issue's attached BrowserLib.zip) with --export=all against the real default lib -- previously aborted with UNREACHABLE executed at .../MLIRTypeHelper.h:2375, now compiles cleanly (exit 0).
  • Compiled all 16 .ts/.d.ts files from the reporter's BrowserLib/runtime/object/Window directory individually with --export=all -- no crashes on any file; remaining failures are ordinary unresolved-symbol errors from files needing sibling imports not present when compiled standalone (expected).
  • Ran the full test/tester/tests suite (365 .ts files) through the fixed compiler (parse + MLIR codegen): zero crashes, zero new failures vs. the pre-fix baseline binary (the 3 pre-existing failures fail identically on both, for unrelated reasons -- missing sibling files / pre-existing issues).

🤖 Generated with Claude Code

…ay types

getFieldTypeByFieldName's ArrayType case only special-cased "length" and
the synthetic index-access field names, then hit llvm_unreachable for any
other field name -- including legitimate extension-method names like
"push"/"pop"/"entries" on the array. This aborts whenever --export=all
forces eager instantiation of a generic class whose body calls array
extension methods (e.g. the default lib's Array<T>/TypedArray<T>, which
Uint8Array/Int32Array alias), as seen when compiling a .d.ts with
`declare function` signatures that reference typed arrays (#231).

Return an empty type instead, matching the "field not found" convention
already used by the tuple/const-tuple cases in the same function, whose
callers (the `in` operator check and extendsType) already treat a null
type as "not present" correctly.
Same defect as the ArrayType case fixed in the previous commit, present
in four more branches of the same function:

- InterfaceType/ClassType: aborted when a string field name matched
  neither a field nor a method, instead of returning "not found" so the
  caller can keep looking (e.g. via extension functions).
- ConstArrayType/StringType: only special-cased "length" (and, for
  ConstArrayType, the synthetic index-access field), then aborted for
  any other field/method name -- e.g. String.fromCharCode.

All five branches now return an empty type for an unresolved field name,
matching the convention already used by the ConstTupleType/TupleType
branches earlier in the same function. This matters in particular for
the UnionType branch (right below), which calls this function per member
and treats a falsy result as "this member doesn't have the field" --
before this fix, a union containing a class/interface/array/string member
would abort the process instead.
@ASDAlexander77 ASDAlexander77 changed the title Fix llvm_unreachable abort resolving array extension-method field names Fix llvm_unreachable aborts resolving unknown field/method names in getFieldTypeByFieldName Jul 15, 2026
The ClassType branch called getInterfaceInfoByFullName() with a class's
full name instead of getClassInfoByFullName(), so it was looking up
class field/method info in the wrong registry. Since classes and
interfaces are registered in separate tables, this lookup essentially
never succeeded for a real class, silently returning "field not found"
for every field/method access on a class type -- affecting the `in`
operator on class instances and extendsType's structural matching of
classes against tuple-shaped constraints (e.g. `T extends { length:
number }`).

ClassInfo's findField/findMethod have a different signature than
InterfaceInfo's (findField takes a bool& out-param and returns a value
rather than a pointer), so the fix updates the call site accordingly
rather than just swapping the lookup function.

Verified against the full tester/tests suite (365 files): no crashes,
no new failures compared to the pre-fix baseline.
@ASDAlexander77
ASDAlexander77 merged commit efacd31 into main Jul 15, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix/issue-231-array-field-unreachable branch July 15, 2026 23:39
ASDAlexander77 added a commit that referenced this pull request Jul 17, 2026
…rage (#241)

* Fix in-operator crash and literal-string field lookup; add regression 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.

* Enhance boolean arithmetic and comparison operations; add regression tests for coercion behavior

* Fix === strict-equality coercion and any==any loose-equality coercion

=== / !== 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>

* Make conditionalExpressionLowering nesting-safe; fix stale 01tuple.ts 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>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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