Summary
Parameter binding is implemented through separate paths for normal functions and generators. PR #56 correctly improves flat array/object destructuring for normal functions and arrow callbacks, but the generator path still supports only identifiers/rest and contains an unchecked rest slice. The new destructuring binder also deep-clones compound values without recursive resource accounting.
This issue tracks the broader work needed to make parameter binding consistent, fallible, and resource-bounded across all callable forms.
Context
PR #56 (d484ac1e9fc6cd7a7d14224f502f349f8ea71e9e) adds per-name flat destructuring in bind_params and fixes the normal-function rest slice by using args.get(i..). Its submitted tests pass for:
- flat array destructuring
- flat object destructuring
Object.entries(...).map(([key, value]) => ...)
Those improvements should be treated separately from the broader deficiencies below.
Verified generator failures
Generator destructuring is ignored
function* values([item]) {
yield item;
}
values([7]).next().value;
Expected: 7
Actual at PR #56 head: undefined
Generator creation has a separate parameter loop that ignores destructuring patterns.
Omitted arguments can panic the Rust host
function* values(prefix, ...rest) {
yield rest.length;
}
values();
Verified panic:
range start index 1 out of range for slice of length 0
The generator binder still uses args[i..].to_vec() rather than a checked slice. This panic is pre-existing and was not introduced by PR #56, but it remains guest-triggerable.
Destructuring semantics
Nullish or incompatible destructuring inputs currently bind names to undefined rather than returning a controlled TypeError:
const read = ({ item }) => item;
let caught = false;
try { read(); } catch (error) { caught = true; }
caught;
Expected JavaScript result: true
Actual: false
The supported subset should either implement the JavaScript behavior or explicitly reject/document the divergence.
Resource impact
The binder clones the full argument and then clones each extracted field. Since arrays and objects are owned recursive Values, repeated aliases can duplicate a large nested value several times inside one call without charging the complete clone size to ResourceTracker.
Example shape:
function fanout({
payload: first,
payload: second,
payload: third
}) {
return 0;
}
fanout({ payload: largeNestedArray });
This is an accidental memory-exhaustion risk, not evidence of malicious contributor code or a filesystem/network/native-code sandbox escape.
Proposed design
- Use one shared, recursive, fallible parameter binder for normal functions, arrows, methods, constructors, and generators.
- Have the binder return
Result<Vec<Value>> so type and resource failures propagate.
- Use checked rest slicing everywhere.
- Define supported behavior for object/array destructuring of
undefined, null, and incompatible values.
- Support or explicitly reject nested patterns, defaults, holes, aliases, and rest properties/elements.
- Charge deep clones against allocation/memory limits before creating local bindings, or move compound values to shared/COW storage.
- Ensure local-slot ordering exactly matches compiler-declared parameter names.
Acceptance criteria
- Normal and generator calls use the same binding semantics.
- Omitted generator rest arguments return an empty array and never panic.
- Generator array/object destructuring binds expected values.
- Nullish destructuring either throws a controlled
TypeError or is rejected at parse/compile time with documented behavior.
- Defaults and subsequent parameter slots remain aligned.
- Nested/unsupported patterns return a controlled error rather than silently binding incorrect values.
- Deep-value binding respects configured resource limits before allocation.
- Regression tests cover normal functions, arrows, methods, constructors, generators, omitted arguments, defaults, rest, nullish values, aliases, and nested patterns.
Related
Summary
Parameter binding is implemented through separate paths for normal functions and generators. PR #56 correctly improves flat array/object destructuring for normal functions and arrow callbacks, but the generator path still supports only identifiers/rest and contains an unchecked rest slice. The new destructuring binder also deep-clones compound values without recursive resource accounting.
This issue tracks the broader work needed to make parameter binding consistent, fallible, and resource-bounded across all callable forms.
Context
PR #56 (
d484ac1e9fc6cd7a7d14224f502f349f8ea71e9e) adds per-name flat destructuring inbind_paramsand fixes the normal-function rest slice by usingargs.get(i..). Its submitted tests pass for:Object.entries(...).map(([key, value]) => ...)Those improvements should be treated separately from the broader deficiencies below.
Verified generator failures
Generator destructuring is ignored
Expected:
7Actual at PR #56 head:
undefinedGenerator creation has a separate parameter loop that ignores destructuring patterns.
Omitted arguments can panic the Rust host
Verified panic:
The generator binder still uses
args[i..].to_vec()rather than a checked slice. This panic is pre-existing and was not introduced by PR #56, but it remains guest-triggerable.Destructuring semantics
Nullish or incompatible destructuring inputs currently bind names to
undefinedrather than returning a controlledTypeError:Expected JavaScript result:
trueActual:
falseThe supported subset should either implement the JavaScript behavior or explicitly reject/document the divergence.
Resource impact
The binder clones the full argument and then clones each extracted field. Since arrays and objects are owned recursive
Values, repeated aliases can duplicate a large nested value several times inside one call without charging the complete clone size toResourceTracker.Example shape:
This is an accidental memory-exhaustion risk, not evidence of malicious contributor code or a filesystem/network/native-code sandbox escape.
Proposed design
Result<Vec<Value>>so type and resource failures propagate.undefined,null, and incompatible values.Acceptance criteria
TypeErroror is rejected at parse/compile time with documented behavior.Related