Skip to content

Commit 0586b3c

Browse files
committed
Fix super(type, foreign) to lookup foreign members
1 parent 9d00ae1 commit 0586b3c

File tree

4 files changed

+54
-15
lines changed

4 files changed

+54
-15
lines changed

docs/user/Interoperability.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ h |= {3: 6} # {1: 2, 3: 6}
8989
h == {1: 2, 3: 6} # True
9090
```
9191

92+
In case of a method defined both in Python and on the foreign object, the Python method wins.
93+
To call the foreign method instead, use `super(type_owning_the_python_method, foreign_object).method(*args)`:
94+
95+
```python
96+
from java.util import ArrayList
97+
l = ArrayList()
98+
l.extend([5, 6, 7])
99+
l.remove(7) # Python list.remove
100+
assert l == [5, 6]
101+
102+
super(list, l).remove(0) # ArrayList#remove(int index)
103+
assert l == [6]
104+
```
105+
92106
See [this section](#interop-types-to-python) for more interop traits and how they map to Python types.
93107

94108
## Interacting with other dynamic languages from Python scripts

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,16 @@ def getLevel(self):
701701
my_lr2 = MyLogRecord(Level.FINEST, message)
702702
assert my_lr2.getLevel() == Level.WARNING
703703

704+
def test_super(self):
705+
from java.util import ArrayList
706+
l = ArrayList()
707+
l.extend([5, 6, 7])
708+
l.remove(7) # Python list.remove
709+
assert l == [5, 6]
710+
711+
super(list, l).remove(0) # ArrayList#remove(int index)
712+
assert l == [6]
713+
704714
def test_java_array(self):
705715
import java
706716
il = java.type("int[]")(20)

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ private static String asJavaPrefixedMethod(String prefix, String member) {
280280
@GenerateInline
281281
@GenerateCached(false)
282282
@ImportStatic(PythonOptions.class)
283-
abstract static class ForeignGetattrNode extends Node {
284-
abstract Object execute(Node inliningTarget, Object object, Object name);
283+
public abstract static class ForeignGetattrNode extends Node {
284+
public abstract Object execute(Node inliningTarget, Object object, Object name);
285285

286286
@Specialization
287287
static Object doIt(Node inliningTarget, Object object, Object memberObj,
@@ -292,7 +292,13 @@ static Object doIt(Node inliningTarget, Object object, Object memberObj,
292292
@Cached PRaiseNode.Lazy raiseNode) {
293293
gil.release(true);
294294
try {
295-
String member = castToString.execute(memberObj);
295+
String member;
296+
try {
297+
member = castToString.execute(memberObj);
298+
} catch (CannotCastException e) {
299+
throw raiseNode.get(inliningTarget).raise(TypeError, ErrorMessages.ATTR_NAME_MUST_BE_STRING, memberObj);
300+
}
301+
296302
if (read.isMemberReadable(object, member)) {
297303
return toPythonNode.executeConvert(read.readMember(object, member));
298304
} else if (PythonLanguage.get(inliningTarget).getEngineOption(PythonOptions.EmulateJython)) {
@@ -308,13 +314,11 @@ static Object doIt(Node inliningTarget, Object object, Object memberObj,
308314
}
309315
}
310316
}
311-
} catch (CannotCastException e) {
312-
throw raiseNode.get(inliningTarget).raise(PythonBuiltinClassType.TypeError, ErrorMessages.ATTR_NAME_MUST_BE_STRING, memberObj);
313317
} catch (UnknownIdentifierException | UnsupportedMessageException | ArityException ignore) {
314318
} finally {
315319
gil.acquire();
316320
}
317-
throw raiseNode.get(inliningTarget).raise(PythonErrorType.AttributeError, ErrorMessages.FOREIGN_OBJ_HAS_NO_ATTR_S, memberObj);
321+
throw raiseNode.get(inliningTarget).raise(AttributeError, ErrorMessages.FOREIGN_OBJ_HAS_NO_ATTR_S, memberObj);
318322
}
319323
}
320324

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/superobject/SuperBuiltins.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import com.oracle.graal.python.builtins.objects.PNone;
6161
import com.oracle.graal.python.builtins.objects.cell.CellBuiltins;
6262
import com.oracle.graal.python.builtins.objects.cell.PCell;
63+
import com.oracle.graal.python.builtins.objects.foreign.ForeignObjectBuiltins.ForeignGetattrNode;
6364
import com.oracle.graal.python.builtins.objects.frame.PFrame;
6465
import com.oracle.graal.python.builtins.objects.function.PArguments;
6566
import com.oracle.graal.python.builtins.objects.function.PKeyword;
@@ -95,6 +96,7 @@
9596
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
9697
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
9798
import com.oracle.graal.python.nodes.object.GetClassNode;
99+
import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
98100
import com.oracle.graal.python.runtime.exception.PException;
99101
import com.oracle.graal.python.runtime.exception.PythonErrorType;
100102
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
@@ -423,7 +425,7 @@ public abstract static class GetattributeNode extends GetAttrBuiltinNode {
423425
@Child private ReadAttributeFromObjectNode readFromDict = ReadAttributeFromObjectNode.createForceType();
424426
@Child private CallSlotDescrGet callGetSlotNode;
425427
@Child private GetTypeNode getType;
426-
@Child private GetObjectNode getObject;
428+
@Child private GetObjectNode getObject = GetObjectNodeGen.create();
427429
@Child private ObjectBuiltins.GetAttributeNode objectGetattributeNode;
428430
@Child private GetMroNode getMroNode;
429431
@Child private IsSameTypeNode isSameTypeNode;
@@ -444,7 +446,9 @@ Object get(VirtualFrame frame, SuperObject self, Object attr,
444446
@Cached GetObjectTypeNode getObjectType,
445447
@Cached CastToTruffleStringCheckedNode castToTruffleStringNode,
446448
@Cached InlinedConditionProfile hasDescrGetProfile,
447-
@Cached InlinedConditionProfile getObjectIsStartObjectProfile) {
449+
@Cached InlinedConditionProfile getObjectIsStartObjectProfile,
450+
@Cached IsForeignObjectNode isForeignObjectNode,
451+
@Cached ForeignGetattrNode foreignGetattrNode) {
448452
Object startType = getObjectType.execute(inliningTarget, self);
449453
if (startType == null) {
450454
return genericGetAttr(frame, self, attr);
@@ -465,12 +469,13 @@ Object get(VirtualFrame frame, SuperObject self, Object attr,
465469
getType = insert(GetTypeNodeGen.create());
466470
}
467471

472+
Object type = getType.executeCached(self);
468473
PythonAbstractClass[] mro = getMro(startType);
469474
/* No need to check the last one: it's gonna be skipped anyway. */
470475
int i = 0;
471476
int n = mro.length;
472477
for (i = 0; i + 1 < n; i++) {
473-
if (isSameType(getType.executeCached(self), mro[i])) {
478+
if (isSameType(type, mro[i])) {
474479
break;
475480
}
476481
}
@@ -493,22 +498,28 @@ Object get(VirtualFrame frame, SuperObject self, Object attr,
493498
CompilerDirectives.transferToInterpreterAndInvalidate();
494499
callGetSlotNode = insert(CallSlotDescrGet.create());
495500
}
496-
if (getObject == null) {
497-
CompilerDirectives.transferToInterpreterAndInvalidate();
498-
getObject = insert(GetObjectNodeGen.create());
499-
}
501+
Object object = getObject.executeCached(self);
500502
Object obj;
501-
if (getObjectIsStartObjectProfile.profile(inliningTarget, getObject.executeCached(self) == startType)) {
503+
if (getObjectIsStartObjectProfile.profile(inliningTarget, object == startType)) {
502504
obj = PNone.NO_VALUE;
503505
} else {
504-
obj = self.getObject();
506+
obj = object;
505507
}
506508
res = callGetSlotNode.executeCached(frame, resSlots.tp_descr_get(), res, obj, startType);
507509
}
508510
return res;
509511
}
510512
}
511513

514+
Object object = getObject.executeCached(self);
515+
if (isForeignObjectNode.execute(inliningTarget, object)) {
516+
try {
517+
return foreignGetattrNode.execute(inliningTarget, object, stringAttr);
518+
} catch (PException e) {
519+
// continue to genericGetAttr()
520+
}
521+
}
522+
512523
return genericGetAttr(frame, self, stringAttr);
513524
}
514525

0 commit comments

Comments
 (0)