From 1f771f68729531bc1805c8ae71595d9fdefb2a85 Mon Sep 17 00:00:00 2001 From: Ronald Brill Date: Wed, 10 Jan 2024 19:06:55 +0100 Subject: [PATCH] Array.prototype[Symbol.iterator] points to the 'values' functions --- src/org/mozilla/javascript/NativeArray.java | 50 ++++++++++--- testsrc/jstests/harmony/for-of.js | 2 +- .../tests/es6/NativeArray3Test.java | 74 +++++++++++++++++++ testsrc/test262.properties | 3 +- 4 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 testsrc/org/mozilla/javascript/tests/es6/NativeArray3Test.java diff --git a/src/org/mozilla/javascript/NativeArray.java b/src/org/mozilla/javascript/NativeArray.java index 9096dec92e..3846494675 100644 --- a/src/org/mozilla/javascript/NativeArray.java +++ b/src/org/mozilla/javascript/NativeArray.java @@ -159,11 +159,6 @@ protected void fillConstructorProperties(IdFunctionObject ctor) { @Override protected void initPrototypeId(int id) { - if (id == SymbolId_iterator) { - initPrototypeMethod(ARRAY_TAG, id, SymbolKey.ITERATOR, "[Symbol.iterator]", 0); - return; - } - String s, fnName = null; int arity; switch (id) { @@ -471,7 +466,6 @@ public Object execIdCall( scope, thisObj, NativeArrayIterator.ARRAY_ITERATOR_TYPE.ENTRIES); case Id_values: - case SymbolId_iterator: thisObj = ScriptRuntime.toObject(cx, scope, thisObj); return new NativeArrayIterator( scope, thisObj, NativeArrayIterator.ARRAY_ITERATOR_TYPE.VALUES); @@ -495,6 +489,42 @@ public boolean has(int index, Scriptable start) { return super.has(index, start); } + @Override + public boolean has(Symbol key, Scriptable start) { + if (SymbolKey.ITERATOR.equals(key)) { + return super.has("values", start); + } + + return super.has(key, start); + } + + @Override + public Object get(Symbol key, Scriptable start) { + if (SymbolKey.ITERATOR.equals(key)) { + return super.get("values", start); + } + + return super.get(key, start); + } + + @Override + public void put(Symbol key, Scriptable start, Object value) { + if (SymbolKey.ITERATOR.equals(key)) { + super.put("values", start, value); + } + + super.put(key, start, value); + } + + @Override + public void delete(Symbol key) { + if (SymbolKey.ITERATOR.equals(key)) { + super.delete("values"); + } + + super.delete(key); + } + private static long toArrayIndex(Object id) { if (id instanceof String) { return toArrayIndex((String) id); @@ -2519,7 +2549,10 @@ private void checkModCount(int modCount) { @Override protected int findPrototypeId(Symbol k) { if (SymbolKey.ITERATOR.equals(k)) { - return SymbolId_iterator; + // "Symbol.iterator" property of the prototype has the "same value" + // as the "values" property. We implement this by returning the + // ID of "values" when the iterator symbol is accessed. + return Id_values; } return 0; } @@ -2729,8 +2762,7 @@ protected int findPrototypeId(String s) { Id_at = 32, Id_flat = 33, Id_flatMap = 34, - SymbolId_iterator = 35, - MAX_PROTOTYPE_ID = SymbolId_iterator; + MAX_PROTOTYPE_ID = Id_flatMap; private static final int ConstructorId_join = -Id_join, ConstructorId_reverse = -Id_reverse, ConstructorId_sort = -Id_sort, diff --git a/testsrc/jstests/harmony/for-of.js b/testsrc/jstests/harmony/for-of.js index af51d6f502..1a22eb7b18 100644 --- a/testsrc/jstests/harmony/for-of.js +++ b/testsrc/jstests/harmony/for-of.js @@ -132,7 +132,7 @@ assertThrows('for each (n of [1,2]) {}', SyntaxError); assertThrows('[n*n for each (n of [1,2])]', SyntaxError); -assertEquals('[Symbol.iterator]', Array.prototype[Symbol.iterator].name); +assertEquals('values', Array.prototype[Symbol.iterator].name); assertEquals('[Symbol.iterator]', String.prototype[Symbol.iterator].name); // should have `value` and `done` property. diff --git a/testsrc/org/mozilla/javascript/tests/es6/NativeArray3Test.java b/testsrc/org/mozilla/javascript/tests/es6/NativeArray3Test.java new file mode 100644 index 0000000000..059996c638 --- /dev/null +++ b/testsrc/org/mozilla/javascript/tests/es6/NativeArray3Test.java @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.javascript.tests.es6; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.tests.Utils; + +/** Tests for NativeArray support. */ +public class NativeArray3Test { + + @Test + public void iteratorPrototype() { + String code = "Array.prototype.values === [][Symbol.iterator]"; + + test(true, code); + } + + @Test + public void iteratorInstances() { + String code = "[1, 2][Symbol.iterator] === [][Symbol.iterator]"; + + test(true, code); + } + + @Test + public void iteratorPrototypeName() { + String code = "Array.prototype.values.name;"; + + test("values", code); + } + + @Test + public void iteratorInstanceName() { + String code = "[][Symbol.iterator].name;"; + + test("values", code); + } + + @Test + public void redefineIterator() { + String code = + "var res = '';\n" + + "var arr = ['hello', 'world'];\n" + + "res += arr[Symbol.iterator].toString().includes('return i;');\n" + + "res += ' - ';\n" + + "arr[Symbol.iterator] = function () { return i; };\n" + + "res += arr[Symbol.iterator].toString().includes('return i;');\n" + + "res += ' - ';\n" + + "delete arr[Symbol.iterator];\n" + + "res += arr[Symbol.iterator].toString().includes('return i;');\n" + + "res;"; + + test("false - true - false", code); + } + + private static void test(Object expected, String js) { + Utils.runWithAllOptimizationLevels( + cx -> { + cx.setLanguageVersion(Context.VERSION_ES6); + ScriptableObject scope = cx.initStandardObjects(); + + Object result = cx.evaluateString(scope, js, "test", 1, null); + assertEquals(expected, result); + + return null; + }); + } +} diff --git a/testsrc/test262.properties b/testsrc/test262.properties index b4869c376d..7ce3d32554 100644 --- a/testsrc/test262.properties +++ b/testsrc/test262.properties @@ -1,6 +1,6 @@ # This is a configuration file for Test262SuiteTest.java. See ./README.md for more info about this file -built-ins/Array 177/2670 (6.63%) +built-ins/Array 176/2670 (6.59%) from/calling-from-valid-1-noStrict.js non-strict Spec pretty clearly says this should be undefined from/elements-deleted-after.js Checking to see if length changed, but spec says it should not from/iter-map-fn-this-non-strict.js non-strict Error propagation needs work in general @@ -169,7 +169,6 @@ built-ins/Array 177/2670 (6.63%) prototype/toLocaleString/primitive_this_value_getter.js strict prototype/unshift/throws-with-string-receiver.js prototype/methods-called-as-functions.js {unsupported: [Symbol.species]} - prototype/Symbol.iterator.js Expects a particular string value Symbol.species 4/4 (100.0%) proto-from-ctor-realm-one.js {unsupported: [Reflect]} proto-from-ctor-realm-two.js {unsupported: [Reflect]}