Browse Source

Fixed the order in which the adder function and the iterator are obtained in {Weak}{Set,Map} constructors.

Dmitry Panov 2 years ago
parent
commit
cb5011b539
8 changed files with 200 additions and 30 deletions
  1. 4 4
      builtin_map.go
  2. 38 0
      builtin_map_test.go
  3. 19 7
      builtin_set.go
  4. 38 0
      builtin_set_test.go
  5. 4 4
      builtin_weakmap.go
  6. 38 0
      builtin_weakmap_test.go
  7. 21 15
      builtin_weakset.go
  8. 38 0
      builtin_weakset_test.go

+ 4 - 4
builtin_map.go

@@ -209,6 +209,10 @@ func (r *Runtime) builtin_newMap(args []Value, newTarget *Object) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := mo.getStr("set", nil)
+			adderFn := toMethod(adder)
+			if adderFn == nil {
+				panic(r.NewTypeError("Map.set in missing"))
+			}
 			iter := r.getIterator(arg, nil)
 			i0 := valueInt(0)
 			i1 := valueInt(1)
@@ -220,10 +224,6 @@ func (r *Runtime) builtin_newMap(args []Value, newTarget *Object) *Object {
 					mo.m.set(k, v)
 				})
 			} else {
-				adderFn := toMethod(adder)
-				if adderFn == nil {
-					panic(r.NewTypeError("Map.set in missing"))
-				}
 				iter.iterate(func(item Value) {
 					itemObj := r.toObject(item)
 					k := itemObj.self.getIdx(i0, nil)

+ 38 - 0
builtin_map_test.go

@@ -102,6 +102,44 @@ func TestMapExportToNonNilMap(t *testing.T) {
 	}
 }
 
+func TestMapGetAdderGetIteratorOrder(t *testing.T) {
+	const SCRIPT = `
+	let getterCalled = 0;
+
+	class M extends Map {
+	    get set() {
+	        getterCalled++;
+	        return null;
+	    }
+	}
+
+	let getIteratorCalled = 0;
+
+	let iterable = {};
+	iterable[Symbol.iterator] = () => {
+	    getIteratorCalled++
+	    return {
+	        next: 1
+	    };
+	}
+
+	let thrown = false;
+
+	try {
+	    new M(iterable);
+	} catch (e) {
+	    if (e instanceof TypeError) {
+	        thrown = true;
+	    } else {
+	        throw e;
+	    }
+	}
+
+	thrown && getterCalled === 1 && getIteratorCalled === 0;
+	`
+	testScript(SCRIPT, valueTrue, t)
+}
+
 func ExampleObject_Export_map() {
 	vm := New()
 	m, err := vm.RunString(`

+ 19 - 7
builtin_set.go

@@ -209,19 +209,31 @@ func (r *Runtime) builtin_newSet(args []Value, newTarget *Object) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := so.getStr("add", nil)
-			iter := r.getIterator(arg, nil)
+			stdArr := r.checkStdArrayIter(arg)
 			if adder == r.global.setAdder {
-				iter.iterate(func(item Value) {
-					so.m.set(item, nil)
-				})
+				if stdArr != nil {
+					for _, v := range stdArr.values {
+						so.m.set(v, nil)
+					}
+				} else {
+					r.getIterator(arg, nil).iterate(func(item Value) {
+						so.m.set(item, nil)
+					})
+				}
 			} else {
 				adderFn := toMethod(adder)
 				if adderFn == nil {
 					panic(r.NewTypeError("Set.add in missing"))
 				}
-				iter.iterate(func(item Value) {
-					adderFn(FunctionCall{This: o, Arguments: []Value{item}})
-				})
+				if stdArr != nil {
+					for _, item := range stdArr.values {
+						adderFn(FunctionCall{This: o, Arguments: []Value{item}})
+					}
+				} else {
+					r.getIterator(arg, nil).iterate(func(item Value) {
+						adderFn(FunctionCall{This: o, Arguments: []Value{item}})
+					})
+				}
 			}
 		}
 	}

+ 38 - 0
builtin_set_test.go

@@ -140,3 +140,41 @@ func TestSetExportToNonNilMap(t *testing.T) {
 		t.Fatal(m)
 	}
 }
+
+func TestSetGetAdderGetIteratorOrder(t *testing.T) {
+	const SCRIPT = `
+	let getterCalled = 0;
+
+	class S extends Set {
+	    get add() {
+	        getterCalled++;
+	        return null;
+	    }
+	}
+
+	let getIteratorCalled = 0;
+
+	let iterable = {};
+	iterable[Symbol.iterator] = () => {
+	    getIteratorCalled++
+	    return {
+	        next: 1
+	    };
+	}
+
+	let thrown = false;
+
+	try {
+	    new S(iterable);
+	} catch (e) {
+	    if (e instanceof TypeError) {
+	        thrown = true;
+	    } else {
+	        throw e;
+	    }
+	}
+
+	thrown && getterCalled === 1 && getIteratorCalled === 0;
+	`
+	testScript(SCRIPT, valueTrue, t)
+}

+ 4 - 4
builtin_weakmap.go

@@ -118,6 +118,10 @@ func (r *Runtime) builtin_newWeakMap(args []Value, newTarget *Object) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := wmo.getStr("set", nil)
+			adderFn := toMethod(adder)
+			if adderFn == nil {
+				panic(r.NewTypeError("WeakMap.set in missing"))
+			}
 			iter := r.getIterator(arg, nil)
 			i0 := valueInt(0)
 			i1 := valueInt(1)
@@ -129,10 +133,6 @@ func (r *Runtime) builtin_newWeakMap(args []Value, newTarget *Object) *Object {
 					wmo.m.set(r.toObject(k), v)
 				})
 			} else {
-				adderFn := toMethod(adder)
-				if adderFn == nil {
-					panic(r.NewTypeError("WeakMap.set in missing"))
-				}
 				iter.iterate(func(item Value) {
 					itemObj := r.toObject(item)
 					k := itemObj.self.getIdx(i0, nil)

+ 38 - 0
builtin_weakmap_test.go

@@ -36,3 +36,41 @@ func TestWeakMap(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestWeakMapGetAdderGetIteratorOrder(t *testing.T) {
+	const SCRIPT = `
+	let getterCalled = 0;
+
+	class M extends WeakMap {
+	    get set() {
+	        getterCalled++;
+	        return null;
+	    }
+	}
+
+	let getIteratorCalled = 0;
+
+	let iterable = {};
+	iterable[Symbol.iterator] = () => {
+	    getIteratorCalled++
+	    return {
+	        next: 1
+	    };
+	}
+
+	let thrown = false;
+
+	try {
+	    new M(iterable);
+	} catch (e) {
+	    if (e instanceof TypeError) {
+	        thrown = true;
+	    } else {
+	        throw e;
+	    }
+	}
+
+	thrown && getterCalled === 1 && getIteratorCalled === 0;
+	`
+	testScript(SCRIPT, valueTrue, t)
+}

+ 21 - 15
builtin_weakset.go

@@ -46,17 +46,6 @@ func (r *Runtime) weakSetProto_has(call FunctionCall) Value {
 	return valueFalse
 }
 
-func (r *Runtime) populateWeakSetGeneric(s *Object, adderValue Value, iterable Value) {
-	adder := toMethod(adderValue)
-	if adder == nil {
-		panic(r.NewTypeError("WeakSet.add is not set"))
-	}
-	iter := r.getIterator(iterable, nil)
-	iter.iterate(func(val Value) {
-		adder(FunctionCall{This: s, Arguments: []Value{val}})
-	})
-}
-
 func (r *Runtime) builtin_newWeakSet(args []Value, newTarget *Object) *Object {
 	if newTarget == nil {
 		panic(r.needNew("WeakSet"))
@@ -74,15 +63,32 @@ func (r *Runtime) builtin_newWeakSet(args []Value, newTarget *Object) *Object {
 	if len(args) > 0 {
 		if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
 			adder := wso.getStr("add", nil)
+			stdArr := r.checkStdArrayIter(arg)
 			if adder == r.global.weakSetAdder {
-				if arr := r.checkStdArrayIter(arg); arr != nil {
-					for _, v := range arr.values {
+				if stdArr != nil {
+					for _, v := range stdArr.values {
 						wso.s.set(r.toObject(v), nil)
 					}
-					return o
+				} else {
+					r.getIterator(arg, nil).iterate(func(item Value) {
+						wso.s.set(r.toObject(item), nil)
+					})
+				}
+			} else {
+				adderFn := toMethod(adder)
+				if adderFn == nil {
+					panic(r.NewTypeError("WeakSet.add in missing"))
+				}
+				if stdArr != nil {
+					for _, item := range stdArr.values {
+						adderFn(FunctionCall{This: o, Arguments: []Value{item}})
+					}
+				} else {
+					r.getIterator(arg, nil).iterate(func(item Value) {
+						adderFn(FunctionCall{This: o, Arguments: []Value{item}})
+					})
 				}
 			}
-			r.populateWeakSetGeneric(o, adder, arg)
 		}
 	}
 	return o

+ 38 - 0
builtin_weakset_test.go

@@ -61,3 +61,41 @@ func TestWeakSetArrayGeneric(t *testing.T) {
 	`
 	testScript(SCRIPT, valueTrue, t)
 }
+
+func TestWeakSetGetAdderGetIteratorOrder(t *testing.T) {
+	const SCRIPT = `
+	let getterCalled = 0;
+
+	class S extends WeakSet {
+	    get add() {
+	        getterCalled++;
+	        return null;
+	    }
+	}
+
+	let getIteratorCalled = 0;
+
+	let iterable = {};
+	iterable[Symbol.iterator] = () => {
+	    getIteratorCalled++
+	    return {
+	        next: 1
+	    };
+	}
+
+	let thrown = false;
+
+	try {
+	    new S(iterable);
+	} catch (e) {
+	    if (e instanceof TypeError) {
+	        thrown = true;
+	    } else {
+	        throw e;
+	    }
+	}
+
+	thrown && getterCalled === 1 && getIteratorCalled === 0;
+	`
+	testScript(SCRIPT, valueTrue, t)
+}