Skip to content

Commit 541cc10

Browse files
hadryyassineelkorchi
authored andcommitted
[GR-59335] Backport to 24.1: Handle mixing overloaded operators with non-numeric primitives
PullRequest: js/3350
2 parents 8def100 + ef70ba9 commit 541cc10

File tree

3 files changed

+45
-26
lines changed

3 files changed

+45
-26
lines changed

Diff for: graal-js/src/com.oracle.truffle.js.test/js/operator_overloading.js

+33-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
@@ -155,6 +155,12 @@ const VectorOperators = Operators({
155155
}
156156
}
157157
return false;
158+
},
159+
"pos"(a) {
160+
return new Vector(a.contents.slice());
161+
},
162+
"neg"(a) {
163+
return new Vector(a.contents.map(e => -e));
158164
}
159165
}, {
160166
right: Number,
@@ -239,9 +245,10 @@ function STR(string) {
239245
}
240246

241247

242-
// Basic tests on vectors: addition, subtraction, equality
248+
// Basic tests on vectors: addition, subtraction, unary negation, equality
243249
assertEqual(V(1, 2, 3) + V(2, 3, 4), V(3, 5, 7));
244250
assertEqual(V(1, 2, 3) - V(2, 3, 4), V(-1, -1, -1));
251+
assertTrue(-V(1, 2, 3) == V(-1, -2, -3))
245252

246253
// Update operators should work too
247254
let A = V(1, 2, 3);
@@ -347,25 +354,31 @@ assertThrows(() => V(1, 2, 3) / V(2, 3, 4), TypeError);
347354
assertThrows(() => 1 + V(1, 2, 3), TypeError);
348355
assertThrows(() => S(1) + V(1, 2, 3), TypeError);
349356
assertThrows(() => V(1, 2, 3) + STR("a"), TypeError);
357+
assertThrows(() => { let v = V(1, 2, 3); v++; }, TypeError);
358+
assertThrows(() => { let v = V(1, 2, 3); v--; }, TypeError);
359+
360+
361+
// Handle null, undefined and non-numeric primitives when dispatching operators that use ToOperand
362+
// (ToPrimitive) internally.
363+
// The cases below are not covered explicitly by the operator overloading proposal, but this
364+
// behavior implied by the proposal spec.
365+
366+
function illegalValueThrowsTypeError(illegalValue) {
367+
assertThrows(() => S(1) + illegalValue, TypeError);
368+
// For equality checks, a missing operator is interpreted as a negative result.
369+
assertFalse(S(1) == illegalValue);
370+
assertTrue(S(1) != illegalValue);
371+
assertThrows(() => S(1) < illegalValue, TypeError);
372+
assertThrows(() => S(1) <= illegalValue, TypeError);
373+
assertThrows(() => S(1) > illegalValue, TypeError);
374+
assertThrows(() => S(1) >= illegalValue, TypeError);
375+
}
350376

351-
352-
// Handle null and undefined when dispatching operators that use ToOperand (ToPrimitive) internally
353-
// the cases below are not covered by the operator overloading proposal
354-
assertThrows(() => S(1) + undefined, TypeError);
355-
assertFalse(S(1) == undefined);
356-
assertTrue(S(1) != undefined);
357-
assertThrows(() => S(1) < undefined, TypeError);
358-
assertThrows(() => S(1) <= undefined, TypeError);
359-
assertThrows(() => S(1) > undefined, TypeError);
360-
assertThrows(() => S(1) >= undefined, TypeError);
361-
362-
assertThrows(() => S(1) + null, TypeError);
363-
assertFalse(S(1) == null);
364-
assertTrue(S(1) != null);
365-
assertThrows(() => S(1) < null, TypeError);
366-
assertThrows(() => S(1) <= null, TypeError);
367-
assertThrows(() => S(1) > null, TypeError);
368-
assertThrows(() => S(1) >= null, TypeError);
377+
illegalValueThrowsTypeError(undefined);
378+
illegalValueThrowsTypeError(null);
379+
illegalValueThrowsTypeError(false);
380+
illegalValueThrowsTypeError(true);
381+
illegalValueThrowsTypeError(Symbol("foo"));
369382

370383

371384
// The Operators function can reject junk input

Diff for: graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/JSOverloadedBinaryNode.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
* Check {@link JSAddNode} for an example of using this node.
7878
* </p>
7979
*/
80+
@ImportStatic(OperatorSet.class)
8081
public abstract class JSOverloadedBinaryNode extends JavaScriptBaseNode {
8182

8283
/**
@@ -295,8 +296,8 @@ protected Object doOverloadedString(JSOverloadedOperatorsObject left,
295296
return performOverloaded(callNode, operatorImplementation, left, right);
296297
}
297298

298-
@Specialization(guards = "isNullOrUndefined(right)")
299-
protected Object doOverloadedNullish(@SuppressWarnings("unused") JSOverloadedOperatorsObject left, @SuppressWarnings("unused") Object right) {
299+
@Specialization(guards = "isUnsupportedPrimitive(right)")
300+
protected Object doOverloadedUnsupportedPrimitive(@SuppressWarnings("unused") JSOverloadedOperatorsObject left, @SuppressWarnings("unused") Object right) {
300301
return missingImplementation();
301302
}
302303

@@ -327,8 +328,8 @@ protected Object doStringOverloaded(Object left,
327328
return performOverloaded(callNode, operatorImplementation, left, right);
328329
}
329330

330-
@Specialization(guards = "isNullOrUndefined(left)")
331-
protected Object doNullishOverloaded(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSOverloadedOperatorsObject right) {
331+
@Specialization(guards = "isUnsupportedPrimitive(left)")
332+
protected Object doUnsupportedPrimitiveOverloaded(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSOverloadedOperatorsObject right) {
332333
return missingImplementation();
333334
}
334335

Diff for: graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/OperatorSet.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -43,6 +43,7 @@
4343
import java.util.Arrays;
4444
import java.util.List;
4545

46+
import com.oracle.truffle.js.runtime.Symbol;
4647
import org.graalvm.collections.EconomicMap;
4748
import org.graalvm.collections.EconomicSet;
4849

@@ -140,7 +141,7 @@ public static Object getOperatorImplementation(JSOverloadedOperatorsObject opera
140141

141142
@TruffleBoundary
142143
public static Object getOperatorImplementation(Object left, Object right, TruffleString operatorName) {
143-
if (JSRuntime.isNullOrUndefined(left) || JSRuntime.isNullOrUndefined(right)) {
144+
if (isUnsupportedPrimitive(left) || isUnsupportedPrimitive(right)) {
144145
return null;
145146
}
146147
OperatorSet leftOperatorSet = getOperatorSet(left);
@@ -164,4 +165,8 @@ public static Object getOperatorImplementation(Object left, Object right, Truffl
164165
}
165166
}
166167
}
168+
169+
public static boolean isUnsupportedPrimitive(Object value) {
170+
return JSRuntime.isNullOrUndefined(value) || value instanceof Boolean || value instanceof Symbol;
171+
}
167172
}

0 commit comments

Comments
 (0)