Skip to content

fix(collections): Map/Set/Weak constructors consume iterables and validate init - #3400

Merged
proggeramlug merged 1 commit into
mainfrom
fix-collections-ctor-2770-2771-2772
May 30, 2026
Merged

proggeramlug merged 1 commit into
mainfrom
fix-collections-ctor-2770-2771-2772

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Closes #2770
Closes #2771
Closes #2772

Implementation

Map/Set/WeakMap/WeakSet constructors now implement spec-faithful
AddEntriesFromIterable / Set-constructor iterable consumption, and the weak
mutators validate at runtime.

New shared module crates/perry-runtime/src/collection_iter.rs:

  • classify_init(value) — null/undefined → empty; any iterable (Array,
    String, Map, Set, custom [Symbol.iterator]) → materialized value array via
    the existing js_for_of_to_array; everything else → throws Node's exact
    TypeError: <type> [<value> ]is not iterable (cannot read property Symbol(Symbol.iterator)) (number/boolean print the value; bigint/symbol/
    function/object print just the type word).
  • is_entry_object / throw_not_entry_object — Map/WeakMap require each
    yielded value to be an object, else TypeError: Iterator value <v> is not an entry object.

Per-collection wiring:

Validation

  • New gap test test-files/test_gap_collections_2770_2771_2772.ts is
    byte-identical to node --experimental-strip-types under the DEFAULT
    auto-optimize compile (covers iterable consumption, short/empty entries,
    null/undefined init, and every TypeError message above).
  • js_map_from_iterable symbol confirmed present in the auto-optimize
    libperry_runtime.a (keepalive survives the whole-program bitcode link).
  • ./scripts/check_file_size.sh → OK; cargo fmt --all -- --check → clean.
  • cargo test -p perry-runtime (896 collection/runtime tests pass; one
    unrelated GC-barrier ordering flake passes in isolation) and
    cargo test -p perry-hir (incl. expr_variant_stable_hash_tags_are_unique)
    green.
  • Regression-checked 7 existing Map/Set/Weak test files
    (test_gap_map_from_map, test_edge_map_set, test_gap_map_set_extended,
    test_gap_weakmap_dynamic, test_gap_for_of_untyped_map_set,
    test_gap_json_map_set, test_gap_map_set_entries_dispatch) — all stay
    byte-identical to node.

Note

new WeakMap(null) instanceof WeakMap returning false is a pre-existing,
orthogonal Perry gap (instanceof WeakMap is false even for new WeakMap());
it is not regressed here. The constructor correctly produces a functional weak
collection for null/undefined init, so the gap test asserts that behavior
functionally (set/get/has) rather than via the unrelated instanceof.

…idate init

Map/Set/WeakMap/WeakSet constructors now run AddEntriesFromIterable-style
semantics: null/undefined init -> empty, any iterable consumed via the
iterator protocol, and non-iterable init throws Node's exact TypeError.
WeakMap/WeakSet mutators validate primitive keys/values at runtime
(not only AST-literal lowering).

Closes #2770, #2771, #2772.
@proggeramlug
proggeramlug merged commit 43fb493 into main May 30, 2026
11 checks passed
@proggeramlug
proggeramlug deleted the fix-collections-ctor-2770-2771-2772 branch May 30, 2026 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant