Selaa lähdekoodia

Replaced map[Value]... with propNameSet because Value can be unhashable (if it's a unicodeString). Fixes #691.

Dmitry Panov 2 viikkoa sitten
vanhempi
sitoutus
2bb4c724c0
4 muutettua tiedostoa jossa 63 lisäystä ja 15 poistoa
  1. 10 0
      builtin_proxy_test.go
  2. 6 8
      destruct.go
  3. 40 0
      object.go
  4. 7 7
      proxy.go

+ 10 - 0
builtin_proxy_test.go

@@ -1273,3 +1273,13 @@ func TestProxyEnumerableSymbols(t *testing.T) {
 
 	testScriptWithTestLib(SCRIPT, valueTrue, t)
 }
+
+func TestProxyUnicodeProps(t *testing.T) {
+	const SCRIPT = `
+    const proxy = new Proxy({}, {
+		ownKeys: () => ["â"]
+	});
+	compareArray(Reflect.ownKeys(proxy), ["â"]);
+	`
+	testScriptWithTestLib(SCRIPT, valueTrue, t)
+}

+ 6 - 8
destruct.go

@@ -1,14 +1,15 @@
 package goja
 
 import (
-	"github.com/dop251/goja/unistring"
 	"reflect"
+
+	"github.com/dop251/goja/unistring"
 )
 
 type destructKeyedSource struct {
 	r        *Runtime
 	wrapped  Value
-	usedKeys map[Value]struct{}
+	usedKeys propNameSet
 }
 
 func newDestructKeyedSource(r *Runtime, wrapped Value) *destructKeyedSource {
@@ -30,10 +31,7 @@ func (d *destructKeyedSource) w() objectImpl {
 }
 
 func (d *destructKeyedSource) recordKey(key Value) {
-	if d.usedKeys == nil {
-		d.usedKeys = make(map[Value]struct{})
-	}
-	d.usedKeys[key] = struct{}{}
+	d.usedKeys.add(key)
 }
 
 func (d *destructKeyedSource) sortLen() int {
@@ -202,7 +200,7 @@ func (i *destructKeyedSourceIter) next() (propIterItem, iterNextFunc) {
 			return item, nil
 		}
 		i.wrapped = next
-		if _, exists := i.d.usedKeys[item.name]; !exists {
+		if !i.d.usedKeys.has(item.name) {
 			return item, i.next
 		}
 	}
@@ -268,7 +266,7 @@ func (d *destructKeyedSource) stringKeys(all bool, accum []Value) []Value {
 func (d *destructKeyedSource) filterUsedKeys(keys []Value) []Value {
 	k := 0
 	for i, key := range keys {
-		if _, exists := d.usedKeys[key]; exists {
+		if d.usedKeys.has(key) {
 			continue
 		}
 		if k != i {

+ 40 - 0
object.go

@@ -1822,3 +1822,43 @@ func (i *privateId) String() string {
 func (i *privateId) string() unistring.String {
 	return privateIdString(i.name)
 }
+
+type propNameSet struct {
+	stringProps map[unistring.String]struct{}
+	symbolProps map[*Symbol]struct{}
+}
+
+func (s *propNameSet) add(prop Value) {
+	if sym, ok := prop.(*Symbol); ok {
+		if s.symbolProps == nil {
+			s.symbolProps = make(map[*Symbol]struct{})
+		}
+		s.symbolProps[sym] = struct{}{}
+	} else {
+		if s.stringProps == nil {
+			s.stringProps = make(map[unistring.String]struct{})
+		}
+		s.stringProps[prop.string()] = struct{}{}
+	}
+}
+
+func (s *propNameSet) has(prop Value) bool {
+	if sym, ok := prop.(*Symbol); ok {
+		_, exists := s.symbolProps[sym]
+		return exists
+	}
+	_, exists := s.stringProps[prop.string()]
+	return exists
+}
+
+func (s *propNameSet) delete(prop Value) {
+	if sym, ok := prop.(*Symbol); ok {
+		delete(s.symbolProps, sym)
+	} else {
+		delete(s.stringProps, prop.string())
+	}
+}
+
+func (s *propNameSet) size() int {
+	return len(s.stringProps) + len(s.symbolProps)
+}

+ 7 - 7
proxy.go

@@ -351,7 +351,7 @@ func (p *proxyObject) preventExtensions(throw bool) bool {
 			p.val.runtime.typeErrorResult(throw, "'preventExtensions' on proxy: trap returned falsish")
 			return false
 		}
-		if te := target.self.isExtensible(); booleanTrapResult && te {
+		if target.self.isExtensible() {
 			panic(p.val.runtime.NewTypeError("'preventExtensions' on proxy: trap returned truish but the proxy target is extensible"))
 		}
 	}
@@ -791,7 +791,7 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
 	if v, ok := p.checkHandler().ownKeys(target); ok {
 		keys := p.val.runtime.toObject(v)
 		var keyList []Value
-		keySet := make(map[Value]struct{})
+		var keySet propNameSet
 		l := toLength(keys.self.getStr("length", nil))
 		for k := int64(0); k < l; k++ {
 			item := keys.self.getIdx(valueInt(k), nil)
@@ -800,16 +800,16 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
 					panic(p.val.runtime.NewTypeError("%s is not a valid property name", item.String()))
 				}
 			}
-			if _, exists := keySet[item]; exists {
+			if keySet.has(item) {
 				panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned duplicate entries"))
 			}
 			keyList = append(keyList, item)
-			keySet[item] = struct{}{}
+			keySet.add(item)
 		}
 		ext := target.self.isExtensible()
 		for item, next := target.self.iterateKeys()(); next != nil; item, next = next() {
-			if _, exists := keySet[item.name]; exists {
-				delete(keySet, item.name)
+			if keySet.has(item.name) {
+				keySet.delete(item.name)
 			} else {
 				if !ext {
 					panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include '%s'", item.name.String()))
@@ -825,7 +825,7 @@ func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
 				}
 			}
 		}
-		if !ext && len(keyList) > 0 && len(keySet) > 0 {
+		if !ext && len(keyList) > 0 && keySet.size() > 0 {
 			panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible"))
 		}