Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow symbol keys in getter/setter in object literal syntax #1749

Merged
merged 2 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5063,7 +5063,10 @@ public static void fillObjectLiteral(
Callable getterOrSetter = (Callable) value;
boolean isSetter = getterSetter == 1;
Integer index = id instanceof Integer ? (Integer) id : null;
String key = index == null ? ScriptRuntime.toString(id) : null;
Object key =
index != null
? null
: (id instanceof Symbol ? id : ScriptRuntime.toString(id));
so.setGetterOrSetter(key, index == null ? 0 : index, getterOrSetter, isSetter);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,8 +559,8 @@ public void setAttributes(Symbol key, int attributes) {

/** Implement the legacy "__defineGetter__" and "__defineSetter__" methods. */
public void setGetterOrSetter(
String name, int index, Callable getterOrSetter, boolean isSetter) {
if (name != null && index != 0) throw new IllegalArgumentException(name);
Object name, int index, Callable getterOrSetter, boolean isSetter) {
if (name != null && index != 0) throw new IllegalArgumentException(name.toString());
checkNotSealed(name, index);

AccessorSlot aSlot;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,215 +15,135 @@

public class ComputedPropertiesTest {
@Test
public void objectWithComputedPropertiesWorkInInterpretedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(-1);
assertObjectWithMixedPropertiesWorks(cx);
}
}

@Test
public void objectWithComputedPropertiesWorkInCompiledMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(0);
assertObjectWithMixedPropertiesWorks(cx);
}
}

@Test
public void objectWithComputedPropertiesWorkInOptimizedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(9);
assertObjectWithMixedPropertiesWorks(cx);
}
}

private static void assertObjectWithMixedPropertiesWorks(Context cx) {
String script =
"\n"
+ "function f(x) { return x; }\n"
+ "\n"
+ "var o = {\n"
+ " a: 1,\n"
+ " 0: 2,\n"
+ " [-1]: 3\n,"
+ " [f('b')]: 4\n"
+ "};\n"
+ "o.a + o[0] + o['-1'] + o.b";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof Number);
assertEquals(10, ((Number) value).intValue());
}

@Test
public void canCoerceFunctionToStringInInterpretedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(-1);
assertCanCoerceFunctionWithComputedPropertiesToString(cx);
}
}

@Test
public void canCoerceFunctionToStringInCompiledMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(0);
assertCanCoerceFunctionWithComputedPropertiesToString(cx);
}
}

private static void assertCanCoerceFunctionWithComputedPropertiesToString(Context cx) {
String script =
"\n"
+ "function f(x) {\n"
+ " var o = {\n"
+ " 1: true,\n"
+ " [2]: false,\n"
+ " [g(x)]: 3\n"
+ " };\n"
+ "}\n"
+ "f.toString()";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof String);
assertEquals(
"function f(x) {\n"
+ " var o = {\n"
+ " 1: true,\n"
+ " [2]: false,\n"
+ " [g(x)]: 3\n"
+ " };\n"
+ "}",
value);
}

@Test
public void computedPropertiesWithSideEffectsWorkInInterpretedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(-1);
assertComputedPropertiesWithSideEffectsWork(cx);
}
}

@Test
public void computedPropertiesWithSideEffectsWorkInCompiledMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(0);
assertComputedPropertiesWithSideEffectsWork(cx);
}
}

@Test
public void computedPropertiesWithSideEffectsWorkInOptimizedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(9);
assertComputedPropertiesWithSideEffectsWork(cx);
}
}

private static void assertComputedPropertiesWithSideEffectsWork(Context cx) {
String script =
"'use strict';\n"
+ "var x = 0;\n"
+ "var o = {\n"
+ " [++x]: 'x',\n"
+ " a: ++x,\n"
+ " [++x]: 'y'\n"
+ "};\n"
+ "o[1] + o.a + o[3]";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertEquals("x2y", value);
}

@Test
public void computedPropertyNameForGetterSetterWorkInInterpretedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(-1);
assertComputedPropertyNameForGetterSetterWorks(cx);
}
}

@Test
public void computedPropertyNameForGetterSetterWorkInCompiled() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(0);
assertComputedPropertyNameForGetterSetterWorks(cx);
}
}

@Test
public void computedPropertyNameForGetterSetterWorkInOptimizedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(9);
assertComputedPropertyNameForGetterSetterWorks(cx);
}
}

private static void assertComputedPropertyNameForGetterSetterWorks(Context cx) {
String script = "var o = { get ['x' + 1]() { return 42; }}; o.x1";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof Number);
assertEquals(42, ((Number) value).intValue());
}

@Test
public void yieldWorksForPropertyValuesInInterpretedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(-1);
assertYieldWorksForPropertyValues(cx);
}
}

@Test
public void yieldWorksForPropertyValuesInCompiledMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(0);
assertYieldWorksForPropertyValues(cx);
}
}

@Test
public void yieldWorksForPropertyValuesInOptimizedMode() {
try (Context cx = Context.enter()) {
cx.setLanguageVersion(Context.VERSION_ES6);
cx.setOptimizationLevel(9);
assertYieldWorksForPropertyValues(cx);
}
}

private static void assertYieldWorksForPropertyValues(Context cx) {
String script =
"\n"
+ "function *gen() {\n"
+ " ({x: yield 1});\n"
+ "}\n"
+ "var g = gen()\n"
+ "var res1 = g.next();\n"
+ "var res2 = g.next();\n"
+ "res1.value === 1 && !res1.done && res2.done\n";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertEquals(Boolean.TRUE, value);
public void objectWithComputedPropertiesWorks() {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
String script =
"\n"
+ "function f(x) { return x; }\n"
+ "\n"
+ "var o = {\n"
+ " a: 1,\n"
+ " 0: 2,\n"
+ " [-1]: 3\n,"
+ " [f('b')]: 4\n"
+ "};\n"
+ "o.a + o[0] + o['-1'] + o.b";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof Number);
assertEquals(10, ((Number) value).intValue());
return null;
});
}

@Test
public void canCoerceFunctionToString() {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
String script =
"\n"
+ "function f(x) {\n"
+ " var o = {\n"
+ " 1: true,\n"
+ " [2]: false,\n"
+ " [g(x)]: 3\n"
+ " };\n"
+ "}\n"
+ "f.toString()";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof String);
assertEquals(
"function f(x) {\n"
+ " var o = {\n"
+ " 1: true,\n"
+ " [2]: false,\n"
+ " [g(x)]: 3\n"
+ " };\n"
+ "}",
value);
return null;
});
}

@Test
public void computedPropertiesWithSideEffectsWork() {
Utils.runWithAllOptimizationLevels(
cx -> {
;
cx.setLanguageVersion(Context.VERSION_ES6);
String script =
"'use strict';\n"
+ "var x = 0;\n"
+ "var o = {\n"
+ " [++x]: 'x',\n"
+ " a: ++x,\n"
+ " [++x]: 'y'\n"
+ "};\n"
+ "o[1] + o.a + o[3]";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertEquals("x2y", value);
return null;
});
}

@Test
public void computedPropertyNameForGetterSetterWork() {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
String script = "var o = { get ['x' + 1]() { return 42; }}; o.x1";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertTrue(value instanceof Number);
assertEquals(42, ((Number) value).intValue());
return null;
});
}

@Test
public void computedPropertyNameAsSymbolForGetterSetterWork() {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
String script =
"var o = { get [Symbol.toStringTag]() { return 'foo'; }}; o.toString()";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertEquals("[object foo]", value);
return null;
});
}

@Test
public void yieldWorksForPropertyValues() {
Utils.runWithAllOptimizationLevels(
cx -> {
cx.setLanguageVersion(Context.VERSION_ES6);
String script =
"\n"
+ "function *gen() {\n"
+ " ({x: yield 1});\n"
+ "}\n"
+ "var g = gen()\n"
+ "var res1 = g.next();\n"
+ "var res2 = g.next();\n"
+ "res1.value === 1 && !res1.done && res2.done\n";

ScriptableObject scope = cx.initStandardObjects();
Object value = cx.evaluateString(scope, script, "test", 1, null);
assertEquals(Boolean.TRUE, value);
return null;
});
}

@Test
Expand Down
Loading
Loading