Skip to content

Commit bc81764

Browse files
committed
[GR-21187] [GR-17600] Throw correct error when setting a slice in a foreign object or the foreign object does not support the argument type
PullRequest: graalpython/872
2 parents bc4518a + cdf813e commit bc81764

File tree

2 files changed

+70
-33
lines changed

2 files changed

+70
-33
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ def test_java_null_is_none():
462462
assert (x != None) == False
463463
assert x is None
464464
assert (x is not None) == False
465-
465+
466466
assert x == y
467467
assert (x != y) == False
468468
assert x is y
@@ -503,4 +503,23 @@ def test_isinstance02():
503503
h = HashMap()
504504
assert isinstance(h, HashMap)
505505
assert isinstance(h, Map)
506-
506+
507+
def test_foreign_slice_setting():
508+
import java
509+
il = java.type("int[]")(20)
510+
try:
511+
il[0:2] = 1
512+
except TypeError:
513+
assert True
514+
else:
515+
assert False, "should throw a type error"
516+
il[0] = 12
517+
assert il[0] == 12
518+
il[0:10] = [10] * 10
519+
assert list(il) == [10] * 10 + [0] * 10, "not equal"
520+
try:
521+
il[0] = 1.2
522+
except TypeError:
523+
assert True
524+
else:
525+
assert False, "should throw a type error again"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/AccessForeignItemNodes.java

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, 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
@@ -58,14 +58,14 @@
5858
import com.oracle.graal.python.nodes.PNodeWithContext;
5959
import com.oracle.graal.python.nodes.PRaiseNode;
6060
import com.oracle.graal.python.nodes.SpecialMethodNames;
61-
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
61+
import com.oracle.graal.python.nodes.control.GetIteratorExpressionNode.GetIteratorNode;
62+
import com.oracle.graal.python.nodes.control.GetNextNode;
6263
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
6364
import com.oracle.graal.python.nodes.interop.PTypeToForeignNode;
6465
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
6566
import com.oracle.graal.python.runtime.PythonOptions;
6667
import com.oracle.graal.python.runtime.exception.PException;
6768
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
68-
import com.oracle.graal.python.runtime.sequence.PSequence;
6969
import com.oracle.truffle.api.CompilerDirectives;
7070
import com.oracle.truffle.api.dsl.Cached;
7171
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -78,6 +78,7 @@
7878
import com.oracle.truffle.api.interop.UnsupportedMessageException;
7979
import com.oracle.truffle.api.interop.UnsupportedTypeException;
8080
import com.oracle.truffle.api.library.CachedLibrary;
81+
import com.oracle.truffle.api.profiles.BranchProfile;
8182

8283
abstract class AccessForeignItemNodes {
8384

@@ -214,26 +215,34 @@ protected abstract static class SetForeignItemNode extends AccessForeignItemBase
214215

215216
public abstract Object execute(VirtualFrame frame, Object object, Object idx, Object value);
216217

217-
@Specialization
218-
public Object doForeignObjectSlice(VirtualFrame frame, Object object, PSlice idxSlice, PSequence pvalues,
219-
@CachedLibrary(limit = "3") InteropLibrary lib,
220-
@Cached("create(__GETITEM__)") LookupAndCallBinaryNode getItemNode,
221-
@Cached("create()") PTypeToForeignNode valueToForeignNode) {
218+
@Specialization(limit = "getCallSiteInlineCacheMaxDepth()")
219+
public Object doForeignObjectSlice(VirtualFrame frame, Object object, PSlice idxSlice, Object pvalues,
220+
@CachedLibrary("object") InteropLibrary lib,
221+
@Cached GetIteratorNode getIterator,
222+
@Cached GetNextNode getNext,
223+
@Cached PTypeToForeignNode valueToForeignNode,
224+
@Cached BranchProfile unsupportedMessage,
225+
@Cached BranchProfile unsupportedType,
226+
@Cached BranchProfile wrongIndex) {
227+
Object value;
228+
SliceInfo mslice;
222229
try {
223-
SliceInfo mslice = materializeSlice(idxSlice, object, lib);
224-
for (int i = mslice.start, j = 0; i < mslice.stop; i += mslice.step, j++) {
225-
Object convertedValue = valueToForeignNode.executeConvert(getItemNode.executeObject(frame, pvalues, j));
226-
writeForeignValue(object, i, convertedValue, lib);
227-
}
228-
return PNone.NONE;
229-
} catch (UnsupportedTypeException | UnsupportedMessageException e) {
230-
throw raise(AttributeError, "%s instance has no attribute '__setitem__'", object);
230+
mslice = materializeSlice(idxSlice, object, lib);
231+
} catch (UnsupportedMessageException e) {
232+
throw raiseNoSetItem(object);
231233
}
234+
Object iter = getIterator.executeWith(frame, pvalues);
235+
for (int i = mslice.start; i < mslice.stop; i += mslice.step) {
236+
value = getNext.execute(frame, iter);
237+
Object convertedValue = valueToForeignNode.executeConvert(value);
238+
writeForeignValue(object, i, convertedValue, lib, unsupportedMessage, unsupportedType, wrongIndex);
239+
}
240+
return PNone.NONE;
232241
}
233242

234-
@Specialization
243+
@Specialization(limit = "getCallSiteInlineCacheMaxDepth()")
235244
public Object doForeignKey(Object object, String key, Object value,
236-
@CachedLibrary(limit = "3") InteropLibrary lib) {
245+
@CachedLibrary("object") InteropLibrary lib) {
237246
if (lib.hasMembers(object)) {
238247
if (lib.isMemberWritable(object, key)) {
239248
try {
@@ -272,33 +281,42 @@ private PException raiseAttributeError(String key) {
272281
public Object doForeignObject(VirtualFrame frame, Object object, Object idx, Object value,
273282
@CachedLibrary("object") InteropLibrary lib,
274283
@CachedLibrary("idx") PythonObjectLibrary pythonLib,
275-
@Cached("create()") PTypeToForeignNode valueToForeignNode) {
276-
try {
277-
int convertedIdx = pythonLib.asSizeWithState(idx, PArguments.getThreadState(frame));
278-
Object convertedValue = valueToForeignNode.executeConvert(value);
279-
writeForeignValue(object, convertedIdx, convertedValue, lib);
280-
return PNone.NONE;
281-
} catch (UnsupportedTypeException e) {
282-
throw raise(AttributeError, "%s instance has no attribute '__setitem__'", object);
283-
}
284+
@Cached PTypeToForeignNode valueToForeignNode,
285+
@Cached BranchProfile unsupportedMessage,
286+
@Cached BranchProfile unsupportedType,
287+
@Cached BranchProfile wrongIndex) {
288+
int convertedIdx = pythonLib.asSizeWithState(idx, PArguments.getThreadState(frame));
289+
Object convertedValue = valueToForeignNode.executeConvert(value);
290+
writeForeignValue(object, convertedIdx, convertedValue, lib, unsupportedMessage, unsupportedType, wrongIndex);
291+
return PNone.NONE;
284292
}
285293

286-
private void writeForeignValue(Object object, int idx, Object value, InteropLibrary libForObject) throws UnsupportedTypeException {
294+
private void writeForeignValue(Object object, int idx, Object value, InteropLibrary libForObject, BranchProfile unsupportedMessage, BranchProfile unsupportedType, BranchProfile wrongIndex) {
287295
if (libForObject.hasArrayElements(object)) {
288296
if (libForObject.isArrayElementWritable(object, idx)) {
289297
try {
290298
libForObject.writeArrayElement(object, idx, value);
291299
return;
292300
} catch (InvalidArrayIndexException ex) {
293-
// fall through
301+
CompilerDirectives.transferToInterpreterAndInvalidate();
302+
throw new IllegalStateException("Array element should be writable, as per test");
294303
} catch (UnsupportedMessageException e) {
295-
CompilerDirectives.transferToInterpreter();
304+
CompilerDirectives.transferToInterpreterAndInvalidate();
296305
throw new IllegalStateException("Array element should be writable, as per test");
306+
} catch (UnsupportedTypeException e) {
307+
unsupportedType.enter();
308+
throw raise(TypeError, "type '%p' is not supported by the foreign object", value);
297309
}
298310
}
311+
wrongIndex.enter();
299312
throw raise(IndexError, "invalid index %s", idx);
300313
}
301-
throw raise(AttributeError, "%s instance has no attribute '__setitem__'", object);
314+
unsupportedMessage.enter();
315+
throw raiseNoSetItem(object);
316+
}
317+
318+
private PException raiseNoSetItem(Object object) {
319+
return raise(AttributeError, "%s instance has no attribute '__setitem__'", object);
302320
}
303321

304322
public static SetForeignItemNode create() {

0 commit comments

Comments
 (0)