Repository navigation
fix(collections): Map/Set/Weak constructors consume iterables and validate init - #3400
Merged
Merged
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2770
Closes #2771
Closes #2772
Implementation
Map/Set/WeakMap/WeakSetconstructors now implement spec-faithfulAddEntriesFromIterable/ Set-constructor iterable consumption, and the weakmutators 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 viathe existing
js_for_of_to_array; everything else → throws Node's exactTypeError: <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 eachyielded value to be an object, else
TypeError: Iterator value <v> is not an entry object.Per-collection wiring:
js_map_from_iterable(f64)reads entry[0]/[1]viathe polymorphic index getter (so
[['k']]and[[]]keepundefinedcomponents); codegen passes the NaN-boxed init value (DOUBLE) instead of an
unboxed
ArrayHeader.#[used]keepalive anchor added (codegen-only symbol).js_set_from_iterablerewritten to consume the materializedarray and throw on non-iterables (no codegen change; it already took f64).
js_weakmap_init_iterable/js_weakset_init_iterableconsume arbitrary iterables + validate entries;js_weakmap_set/js_weakset_addvalidate keys/values at runtime and throwInvalid value used as weak map key/Invalid value used in weak set. TheAST-literal-only primitive throw in HIR lowering was removed so literal and
dynamic primitives are rejected uniformly with the correct distinct messages.
Validation
test-files/test_gap_collections_2770_2771_2772.tsisbyte-identical to
node --experimental-strip-typesunder the DEFAULTauto-optimize compile (covers iterable consumption, short/empty entries,
null/undefined init, and every TypeError message above).
js_map_from_iterablesymbol confirmed present in the auto-optimizelibperry_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; oneunrelated GC-barrier ordering flake passes in isolation) and
cargo test -p perry-hir(incl.expr_variant_stable_hash_tags_are_unique)green.
(
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 staybyte-identical to node.
Note
new WeakMap(null) instanceof WeakMapreturningfalseis a pre-existing,orthogonal Perry gap (
instanceof WeakMapis false even fornew WeakMap());it is not regressed here. The constructor correctly produces a functional weak
collection for
null/undefinedinit, so the gap test asserts that behaviorfunctionally (set/get/has) rather than via the unrelated
instanceof.