Skip to content

Commit

Permalink
Fixed the handling of Symbol properties in destructuring assignments. F…
Browse files Browse the repository at this point in the history
…ixes dop251#312.

Signed-off-by: Gabri <gabriele.cimato@gmail.com>
  • Loading branch information
dop251 authored and Gabri3l committed Jan 24, 2022
1 parent f87bc71 commit c8bd2d4
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 23 deletions.
20 changes: 20 additions & 0 deletions builtin_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1260,3 +1260,23 @@ func TestProxy_proxy_createTargetNotCallable(t *testing.T) {

testScript1(TESTLIB+SCRIPT, _undefined, t)
}

func TestProxyEnumerableSymbols(t *testing.T) {
const SCRIPT = `
var getOwnKeys = [];
var ownKeysResult = [Symbol(), "foo", "0"];
var proxy = new Proxy({}, {
getOwnPropertyDescriptor: function(_target, key) {
getOwnKeys.push(key);
},
ownKeys: function() {
return ownKeysResult;
},
});
let {...$} = proxy;
compareArray(getOwnKeys, ownKeysResult);
`

testScript1(TESTLIB+SCRIPT, valueTrue, t)
}
36 changes: 26 additions & 10 deletions destruct.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
type destructKeyedSource struct {
r *Runtime
wrapped Value
usedKeys map[unistring.String]struct{}
usedKeys map[Value]struct{}
}

func newDestructKeyedSource(r *Runtime, wrapped Value) *destructKeyedSource {
Expand All @@ -29,9 +29,9 @@ func (d *destructKeyedSource) w() objectImpl {
return d.wrapped.ToObject(d.r).self
}

func (d *destructKeyedSource) recordKey(key unistring.String) {
func (d *destructKeyedSource) recordKey(key Value) {
if d.usedKeys == nil {
d.usedKeys = make(map[unistring.String]struct{})
d.usedKeys = make(map[Value]struct{})
}
d.usedKeys[key] = struct{}{}
}
Expand All @@ -53,30 +53,32 @@ func (d *destructKeyedSource) className() string {
}

func (d *destructKeyedSource) getStr(p unistring.String, receiver Value) Value {
d.recordKey(p)
d.recordKey(stringValueFromRaw(p))
return d.w().getStr(p, receiver)
}

func (d *destructKeyedSource) getIdx(p valueInt, receiver Value) Value {
d.recordKey(p.string())
d.recordKey(p.toString())
return d.w().getIdx(p, receiver)
}

func (d *destructKeyedSource) getSym(p *Symbol, receiver Value) Value {
d.recordKey(p)
return d.w().getSym(p, receiver)
}

func (d *destructKeyedSource) getOwnPropStr(u unistring.String) Value {
d.recordKey(u)
d.recordKey(stringValueFromRaw(u))
return d.w().getOwnPropStr(u)
}

func (d *destructKeyedSource) getOwnPropIdx(v valueInt) Value {
d.recordKey(v.string())
d.recordKey(v.toString())
return d.w().getOwnPropIdx(v)
}

func (d *destructKeyedSource) getOwnPropSym(symbol *Symbol) Value {
d.recordKey(symbol)
return d.w().getOwnPropSym(symbol)
}

Expand Down Expand Up @@ -204,7 +206,7 @@ func (i *destructKeyedSourceIter) next() (propIterItem, iterNextFunc) {
return item, nil
}
i.wrapped = next
if _, exists := i.d.usedKeys[item.name]; !exists {
if _, exists := i.d.usedKeys[stringValueFromRaw(item.name)]; !exists {
return item, i.next
}
}
Expand Down Expand Up @@ -244,12 +246,26 @@ func (d *destructKeyedSource) ownKeys(all bool, accum []Value) []Value {
return accum
}

func (d *destructKeyedSource) filterUsedKeys(keys []Value) []Value {
k := 0
for i, key := range keys {
if _, exists := d.usedKeys[key]; exists {
continue
}
if k != i {
keys[k] = key
}
k++
}
return keys[:k]
}

func (d *destructKeyedSource) ownSymbols(all bool, accum []Value) []Value {
return d.w().ownSymbols(all, accum)
return d.filterUsedKeys(d.w().ownSymbols(all, accum))
}

func (d *destructKeyedSource) ownPropertyKeys(all bool, accum []Value) []Value {
return d.ownSymbols(all, d.ownKeys(all, accum))
return d.filterUsedKeys(d.w().ownPropertyKeys(all, accum))
}

func (d *destructKeyedSource) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
Expand Down
19 changes: 18 additions & 1 deletion proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,23 @@ func (p *proxyObject) deleteSym(s *Symbol, throw bool) bool {

func (p *proxyObject) ownPropertyKeys(all bool, _ []Value) []Value {
if v, ok := p.proxyOwnKeys(); ok {
if !all {
k := 0
for i, key := range v {
prop := p.val.getOwnProp(key)
if prop == nil {
continue
}
if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
continue
}
if k != i {
v[k] = v[i]
}
k++
}
v = v[:k]
}
return v
}
return p.target.self.ownPropertyKeys(all, nil)
Expand Down Expand Up @@ -992,7 +1009,7 @@ func (p *proxyObject) ownKeys(all bool, _ []Value) []Value { // we can assume ac

func (p *proxyObject) ownSymbols(all bool, accum []Value) []Value {
if vals, ok := p.proxyOwnKeys(); ok {
res := p.filterKeys(vals, true, true)
res := p.filterKeys(vals, all, true)
if accum == nil {
return res
}
Expand Down
12 changes: 12 additions & 0 deletions runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,18 @@ func TestStrToInt32(t *testing.T) {
}
}

func TestDestructSymbol(t *testing.T) {
const SCRIPT = `
var S = Symbol("S");
var s, rest;
({[S]: s, ...rest} = {[S]: true, test: 1});
assert.sameValue(s, true, "S");
assert(deepEqual(rest, {test: 1}), "rest");
`
testScript1(TESTLIBX+SCRIPT, _undefined, t)
}

/*
func TestArrayConcatSparse(t *testing.T) {
function foo(a,b,c)
Expand Down
1 change: 1 addition & 0 deletions tc39_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ var (
"sec-functiondeclarations-in-ifstatement-statement-clauses",
"sec-evaldeclarationinstantiation",
"sec-integer-indexed-exotic-objects-defineownproperty-p-desc",
"sec-destructuring-binding-patterns",
}
)

Expand Down
15 changes: 3 additions & 12 deletions vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3789,18 +3789,9 @@ func (r *Runtime) copyDataProperties(target, source Value) {
return
}
sourceObj := source.ToObject(r)
iter := &enumerableIter{
wrapped: sourceObj.self.enumerateOwnKeys(),
}

for item, next := iter.next(); next != nil; item, next = next() {
v := nilSafe(sourceObj.self.getStr(item.name, nil))
createDataPropertyOrThrow(targetObj, stringValueFromRaw(item.name), v)
}

for _, sym := range sourceObj.self.ownSymbols(false, nil) {
v := nilSafe(sourceObj.self.getSym(sym.(*Symbol), nil))
createDataPropertyOrThrow(targetObj, sym, v)
for _, key := range sourceObj.self.ownPropertyKeys(false, nil) {
v := nilSafe(sourceObj.get(key, nil))
createDataPropertyOrThrow(targetObj, key, v)
}
}

Expand Down

0 comments on commit c8bd2d4

Please sign in to comment.