Skip to content

Commit 011fbd5

Browse files
committed
[GR-23218] Make test_descr pass - subclassing_does_not_duplicate_dict_descriptors.
PullRequest: graalpython/1245
2 parents 4a96bfe + 5e593ea commit 011fbd5

File tree

16 files changed

+345
-139
lines changed

16 files changed

+345
-139
lines changed

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,48 @@ class MyDict(dict):
252252
(MyDict({"1":1, "2": 2}), TPFLAGS_DICT_SUBCLASS),
253253
]:
254254
assert type(x).__flags__ & flag, "masked __flags__ = {}, expected {}".format(type(x).__flags__ & flag, flag)
255+
256+
def test_dict():
257+
def dict_element_raises(o, err):
258+
raised = False
259+
try:
260+
o['__dict__']
261+
except err:
262+
raised = True
263+
assert raised
264+
265+
class Base:
266+
pass
267+
268+
class Sub(Base):
269+
pass
270+
271+
str(type(Base.__dict__['__dict__'])) == "<class 'get_set_desc'>"
272+
dict_element_raises(Sub.__dict__, KeyError)
273+
Base().__dict__ == {}
274+
Sub().__dict__ == {}
275+
276+
class BaseSlots:
277+
__slots__ = ['a']
278+
279+
dict_element_raises(BaseSlots.__dict__, KeyError)
280+
raised = False
281+
try:
282+
BaseSlots().__dict__
283+
except AttributeError:
284+
raised = True
285+
assert raised
286+
287+
class SubSlots(BaseSlots):
288+
pass
289+
290+
str(type(SubSlots.__dict__['__dict__'])) == "<class 'get_set_desc'>"
291+
assert SubSlots().__dict__ == {}
292+
293+
class SubSlots(BaseSlots, Base):
294+
pass
295+
296+
str(type(SubSlots.__dict__['__dict__'])) == "<class 'get_set_desc'>"
297+
assert SubSlots().__dict__ == {}
298+
299+

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_descr.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_rmul
7171
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_set_and_no_get
7272
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_set_class
73+
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_set_dict
7374
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_slices
7475
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_slots_descriptor
7576
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_slots_trash
@@ -81,6 +82,7 @@
8182
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_str_operations
8283
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_str_subclass_as_dict_key
8384
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_subclass_propagation
85+
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_subclassing_does_not_duplicate_dict_descriptors
8486
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_testcapi_no_segfault
8587
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_type___getattribute__
8688
*graalpython.lib-python.3.test.test_descr.ClassPropertiesAndMethods.test_uninitialized_modules

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_ipaddress.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_not_an_index_issue15559
1313
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_octet_length
1414
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_octet_limit
15+
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_packed
1516
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_pickle
1617
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v4.test_weakref
1718
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_bad_address_split_v6_leading_colon
@@ -32,6 +33,7 @@
3233
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_negative_ints_rejected
3334
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_network_passed_as_address
3435
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_not_an_index_issue15559
36+
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_packed
3537
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_part_length
3638
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_pickle
3739
*graalpython.lib-python.3.test.test_ipaddress.AddressTestCase_v6.test_weakref
@@ -59,6 +61,7 @@
5961
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_netmask_in_tuple_errors
6062
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_no_mask
6163
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_not_an_index_issue15559
64+
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_packed
6265
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_pickle
6366
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_split_netmask
6467
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v4.test_valid_netmask
@@ -74,6 +77,7 @@
7477
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_netmask_in_tuple_errors
7578
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_no_mask
7679
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_not_an_index_issue15559
80+
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_packed
7781
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_pickle
7882
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_split_netmask
7983
*graalpython.lib-python.3.test.test_ipaddress.InterfaceTestCase_v6.test_valid_netmask
@@ -159,6 +163,7 @@
159163
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_netmask_in_tuple_errors
160164
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_no_mask
161165
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_not_an_index_issue15559
166+
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_packed
162167
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_pickle
163168
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_split_netmask
164169
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v4.test_subnet_of
@@ -177,6 +182,7 @@
177182
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_netmask_in_tuple_errors
178183
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_no_mask
179184
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_not_an_index_issue15559
185+
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_packed
180186
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_pickle
181187
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_split_netmask
182188
*graalpython.lib-python.3.test.test_ipaddress.NetworkTestCase_v6.test_subnet_of

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
139139
import com.oracle.graal.python.builtins.objects.function.PFunction;
140140
import com.oracle.graal.python.builtins.objects.function.PKeyword;
141+
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptor;
141142
import com.oracle.graal.python.builtins.objects.getsetdescriptor.HiddenKeyDescriptor;
142143
import com.oracle.graal.python.builtins.objects.getsetdescriptor.HiddenPythonKey;
143144
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -149,6 +150,7 @@
149150
import com.oracle.graal.python.builtins.objects.module.PythonModule;
150151
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
151152
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltinsFactory;
153+
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltinsFactory.DictNodeGen;
152154
import com.oracle.graal.python.builtins.objects.object.PythonObject;
153155
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
154156
import com.oracle.graal.python.builtins.objects.range.PBigRange;
@@ -191,6 +193,8 @@
191193
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
192194
import com.oracle.graal.python.nodes.expression.CastToListExpressionNode.CastToListNode;
193195
import com.oracle.graal.python.nodes.frame.ReadCallerFrameNode;
196+
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
197+
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode.StandaloneBuiltinFactory;
194198
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
195199
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
196200
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -220,6 +224,7 @@
220224
import com.oracle.truffle.api.CompilerDirectives;
221225
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
222226
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
227+
import com.oracle.truffle.api.RootCallTarget;
223228
import com.oracle.truffle.api.Truffle;
224229
import com.oracle.truffle.api.dsl.Cached;
225230
import com.oracle.truffle.api.dsl.Cached.Shared;
@@ -2080,7 +2085,8 @@ Object typeNew(VirtualFrame frame, Object cls, Object wName, PTuple bases, PDict
20802085
@Cached CallNode callSetNameNode,
20812086
@Cached CallNode callInitSubclassNode,
20822087
@Cached CallNode callNewFuncNode,
2083-
@Cached GetBestBaseClassNode getBestBaseNode) {
2088+
@Cached GetBestBaseClassNode getBestBaseNode,
2089+
@Cached("create(__DICT__)") LookupAttributeInMRONode getDictAttrNode) {
20842090
// Determine the proper metatype to deal with this
20852091
String name = castStr.execute(wName);
20862092
Object metaclass = calculate_metaclass(frame, cls, bases, lib);
@@ -2095,7 +2101,7 @@ Object typeNew(VirtualFrame frame, Object cls, Object wName, PTuple bases, PDict
20952101
}
20962102

20972103
try {
2098-
PythonClass newType = typeMetaclass(frame, name, bases, namespace, metaclass, nslib, getBestBaseNode);
2104+
PythonClass newType = typeMetaclass(frame, name, bases, namespace, metaclass, nslib, getDictAttrNode, getBestBaseNode);
20992105

21002106
for (DictEntry entry : nslib.entries(namespace.getDictStorage())) {
21012107
Object setName = getSetNameNode.execute(entry.value);
@@ -2180,7 +2186,7 @@ private String getModuleNameFromGlobals(PythonObject globals, HashingStorageLibr
21802186
}
21812187
}
21822188

2183-
private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases, PDict namespace, Object metaclass, HashingStorageLibrary nslib,
2189+
private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases, PDict namespace, Object metaclass, HashingStorageLibrary nslib, LookupAttributeInMRONode getDictAttrNode,
21842190
GetBestBaseClassNode getBestBaseNode) {
21852191
Object[] array = ensureGetObjectArrayNode().execute(bases);
21862192

@@ -2237,6 +2243,7 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
22372243
if (slots[0] == null) {
22382244
// takes care of checking if we may_add_dict and adds it if needed
22392245
addDictIfNative(frame, pythonClass);
2246+
addDictDescrAttribute(basesArray, getDictAttrNode, pythonClass);
22402247
// TODO: tfel - also deal with weaklistoffset
22412248
} else {
22422249
// have slots
@@ -2276,6 +2283,7 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
22762283
throw raise(TypeError, ErrorMessages.SLOT_DISALLOWED_WE_GOT_ONE, "__dict__");
22772284
}
22782285
addDict = true;
2286+
addDictDescrAttribute(basesArray, getDictAttrNode, pythonClass);
22792287
} else {
22802288
// TODO: check for __weakref__
22812289
// TODO avoid if native slots are inherited
@@ -2309,6 +2317,41 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
23092317
return pythonClass;
23102318
}
23112319

2320+
private void addDictDescrAttribute(PythonAbstractClass[] basesArray, LookupAttributeInMRONode getDictAttrNode, PythonClass pythonClass) {
2321+
if ((!hasPythonClassBases(basesArray) && getDictAttrNode.execute(pythonClass) == PNone.NO_VALUE) || basesHaveSlots(basesArray)) {
2322+
CompilerDirectives.transferToInterpreterAndInvalidate();
2323+
Builtin dictBuiltin = ObjectBuiltins.DictNode.class.getAnnotation(Builtin.class);
2324+
BuiltinFunctionRootNode rootNode = new BuiltinFunctionRootNode(getCore().getLanguage(), dictBuiltin, new StandaloneBuiltinFactory<PythonBinaryBuiltinNode>(DictNodeGen.create()), true);
2325+
RootCallTarget callTarget = PythonUtils.getOrCreateCallTarget(rootNode);
2326+
PBuiltinFunction function = getCore().factory().createBuiltinFunction(__DICT__, pythonClass, 1, callTarget);
2327+
GetSetDescriptor desc = factory().createGetSetDescriptor(function, function, __DICT__, pythonClass, true);
2328+
pythonClass.setAttribute(__DICT__, desc);
2329+
}
2330+
}
2331+
2332+
private static boolean basesHaveSlots(PythonAbstractClass[] basesArray) {
2333+
// this is merely based on empirical observation
2334+
// see also test_type.py#test_dict()
2335+
for (PythonAbstractClass c : basesArray) {
2336+
// TODO: what about native?
2337+
if (c instanceof PythonClass) {
2338+
if (((PythonClass) c).getAttribute(__SLOTS__) != PNone.NO_VALUE) {
2339+
return true;
2340+
}
2341+
}
2342+
}
2343+
return false;
2344+
}
2345+
2346+
private static boolean hasPythonClassBases(PythonAbstractClass[] basesArray) {
2347+
for (PythonAbstractClass c : basesArray) {
2348+
if (c instanceof PythonClass) {
2349+
return true;
2350+
}
2351+
}
2352+
return false;
2353+
}
2354+
23122355
private void copyDictSlots(PythonClass pythonClass, PDict namespace, HashingStorageLibrary nslib, Object[] slots, boolean[] qualnameSet) {
23132356
// copy the dictionary slots over, as CPython does through PyDict_Copy
23142357
// Also check for a __slots__ sequence variable in dict

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PythonCextBuiltins.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@
115115
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.GetNativeNullNode;
116116
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.MayRaiseBinaryNode;
117117
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.MayRaiseNode;
118-
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.MayRaiseNodeFactory;
119118
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.MayRaiseTernaryNode;
120119
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.MayRaiseUnaryNode;
121120
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ObjectUpcallNode;
@@ -221,6 +220,7 @@
221220
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
222221
import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
223222
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
223+
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode.StandaloneBuiltinFactory;
224224
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
225225
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
226226
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -2325,17 +2325,17 @@ Object make(PFunction func, Object errorResult,
23252325
switch (funcSignature.getMaxNumOfPositionalArgs()) {
23262326
case 1:
23272327
rootNode = new BuiltinFunctionRootNode(lang, unaryBuiltin,
2328-
new MayRaiseNodeFactory<PythonUnaryBuiltinNode>(MayRaiseUnaryNodeGen.create(func, errorResult)),
2328+
new StandaloneBuiltinFactory<PythonUnaryBuiltinNode>(MayRaiseUnaryNodeGen.create(func, errorResult)),
23292329
true);
23302330
break;
23312331
case 2:
23322332
rootNode = new BuiltinFunctionRootNode(lang, binaryBuiltin,
2333-
new MayRaiseNodeFactory<PythonBinaryBuiltinNode>(MayRaiseBinaryNodeGen.create(func, errorResult)),
2333+
new StandaloneBuiltinFactory<PythonBinaryBuiltinNode>(MayRaiseBinaryNodeGen.create(func, errorResult)),
23342334
true);
23352335
break;
23362336
case 3:
23372337
rootNode = new BuiltinFunctionRootNode(lang, ternaryBuiltin,
2338-
new MayRaiseNodeFactory<PythonTernaryBuiltinNode>(MayRaiseTernaryNodeGen.create(func, errorResult)),
2338+
new StandaloneBuiltinFactory<PythonTernaryBuiltinNode>(MayRaiseTernaryNodeGen.create(func, errorResult)),
23392339
true);
23402340
break;
23412341
default:
@@ -2344,7 +2344,7 @@ Object make(PFunction func, Object errorResult,
23442344
}
23452345
if (rootNode == null) {
23462346
rootNode = new BuiltinFunctionRootNode(lang, varargsBuiltin,
2347-
new MayRaiseNodeFactory<PythonBuiltinNode>(new MayRaiseNode(func, errorResult)),
2347+
new StandaloneBuiltinFactory<PythonBuiltinNode>(new MayRaiseNode(func, errorResult)),
23482348
true);
23492349
}
23502350

0 commit comments

Comments
 (0)