You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
new Map(init) currently lowers any provided argument to Expr::MapNewFromArray and routes it through js_map_from_array. The runtime supports two narrow shapes:
an Array whose elements are nested [key, value] arrays,
That still misses Node's Map constructor semantics:
any iterable of entry objects should be accepted, not just arrays / Maps,
short entry objects such as ['key'] or [] should still add entries with undefined values/keys,
malformed entry values such as 1 should throw TypeError, not be skipped,
non-null, non-undefined, non-iterable init values should throw TypeError, not produce an empty/partial Map.
Node behavior
Checked with Node v25.9.0:
constm=newMap([['a',1],['b',2]]);m.size;// 2m.get('a');// 1m.get('b');// 2constclone=newMap(m);clone.size;// 2clone.get('a');// 1constfromSet=newMap(newSet([['s',3]]));fromSet.size;// 1fromSet.get('s');// 3constshort=newMap([['short']]);short.size;// 1short.has('short');// trueshort.get('short')===undefined;// trueconstemptyPair=newMap([[]]);emptyPair.size;// 1emptyPair.has(undefined);// trueemptyPair.get(undefined)===undefined;// truenewMap(null).size;// 0newMap(undefined).size;// 0newMap(1);// TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator))newMap({a: 1});// TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))newMap([1]);// TypeError: Iterator value 1 is not an entry objectnewMap(Symbol('x'));// TypeError: symbol is not iterable (cannot read property Symbol(Symbol.iterator))
Perry implementation
Lowering sends any provided Map constructor argument to the same runtime helper:
crates/perry-hir/src/lower/expr_new.rs:283 handles new Map() / new Map(entries).
crates/perry-hir/src/lower/expr_new.rs:295 returns Expr::MapNew for no arguments.
crates/perry-hir/src/lower/expr_new.rs:298 returns Expr::MapNewFromArray(firstArg) for any argument.
crates/perry-codegen/src/expr/misc_methods.rs:57 lowers Expr::MapNewFromArray by unboxing the argument and calling js_map_from_array.
The runtime helper documents and implements only the narrow supported shapes:
crates/perry-runtime/src/map.rs:1191 says js_map_from_array supports array-of-pair arrays and another Map.
crates/perry-runtime/src/map.rs:1223 otherwise treats the input as an ArrayHeader and iterates by array length.
crates/perry-runtime/src/map.rs:1236 / :1247 skip entries whose element is not an array-like pointer, so new Map([1]) cannot throw the required TypeError.
crates/perry-runtime/src/map.rs:1252 / :1254 skip nested arrays with fewer than two elements, so new Map([['short']]) and new Map([[]]) lose entries that Node keeps with undefined components.
Expected fix direction
The Map constructor path should implement AddEntriesFromIterable semantics more closely:
treat null and undefined as empty init,
obtain and consume a real iterator for other init values,
throw TypeError for non-iterable init values,
require each iterator value to be an object and throw when it is not,
read entry properties 0 and 1 without requiring an array length of at least 2,
keep the existing fast paths for array-of-pairs and new Map(existingMap) when they preserve the same behavior.
Duplicate search
Searched existing issues/PRs for:
Map constructor iterable
new Map iterable
Map entries constructor
new Map malformed entry
Map constructor Set iterable
Map constructor TypeError
js_map_from_array
PR search for Map constructor iterable OR js_map_from_array
No existing issue covered the remaining constructor semantics. Related but not duplicate: PR #1871 fixed only new Map(existingMap) copying, and #2645 tracks Headers constructor iterable/cloning behavior rather than Map itself.
Summary
new Map(init)currently lowers any provided argument toExpr::MapNewFromArrayand routes it throughjs_map_from_array. The runtime supports two narrow shapes:[key, value]arrays,That still misses Node's Map constructor semantics:
['key']or[]should still add entries withundefinedvalues/keys,1should throwTypeError, not be skipped,TypeError, not produce an empty/partial Map.Node behavior
Checked with Node v25.9.0:
Perry implementation
Lowering sends any provided Map constructor argument to the same runtime helper:
crates/perry-hir/src/lower/expr_new.rs:283handlesnew Map()/new Map(entries).crates/perry-hir/src/lower/expr_new.rs:295returnsExpr::MapNewfor no arguments.crates/perry-hir/src/lower/expr_new.rs:298returnsExpr::MapNewFromArray(firstArg)for any argument.crates/perry-codegen/src/expr/misc_methods.rs:57lowersExpr::MapNewFromArrayby unboxing the argument and callingjs_map_from_array.The runtime helper documents and implements only the narrow supported shapes:
crates/perry-runtime/src/map.rs:1191saysjs_map_from_arraysupports array-of-pair arrays and another Map.crates/perry-runtime/src/map.rs:1204detects registered Map arguments and copies them, which is the fix(runtime): new Map(existingMap) copies entries (#33/#321) — needed by, but not sufficient for, Context/Layer #1871 fix.crates/perry-runtime/src/map.rs:1223otherwise treats the input as an ArrayHeader and iterates by array length.crates/perry-runtime/src/map.rs:1236/:1247skip entries whose element is not an array-like pointer, sonew Map([1])cannot throw the required TypeError.crates/perry-runtime/src/map.rs:1252/:1254skip nested arrays with fewer than two elements, sonew Map([['short']])andnew Map([[]])lose entries that Node keeps withundefinedcomponents.Expected fix direction
The Map constructor path should implement
AddEntriesFromIterablesemantics more closely:nullandundefinedas empty init,TypeErrorfor non-iterable init values,0and1without requiring an array length of at least 2,new Map(existingMap)when they preserve the same behavior.Duplicate search
Searched existing issues/PRs for:
Map constructor iterablenew Map iterableMap entries constructornew Map malformed entryMap constructor Set iterableMap constructor TypeErrorjs_map_from_arrayMap constructor iterable OR js_map_from_arrayNo existing issue covered the remaining constructor semantics. Related but not duplicate: PR #1871 fixed only
new Map(existingMap)copying, and #2645 tracksHeadersconstructor iterable/cloning behavior rather thanMapitself.