Skip to content

Commit 69b1f8f

Browse files
committed
__dict__ and __weakref__ has to be stored in __slots__
1 parent b1d349f commit 69b1f8f

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

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

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -55,7 +55,45 @@ def test_uninitialized_slot(self):
5555
obj.world
5656
obj.world = "world"
5757
self.assertEqual(obj.world, "world")
58+
59+
def test_dict_and_weakref_are_listed_in_slots(self):
60+
class D: __slots__ = ['__dict__']
61+
self.assertEqual(tuple(D.__slots__), ('__dict__',))
62+
self.assertEqual(tuple(D().__slots__), ('__dict__',))
5863

64+
class WR: __slots__ = ['__weakref__']
65+
self.assertEqual(tuple(WR.__slots__), ('__weakref__',))
66+
self.assertEqual(tuple(WR().__slots__), ('__weakref__',))
5967

68+
class DWR: __slots__ = ['__dict__', '__weakref__']
69+
self.assertEqual(tuple(DWR.__slots__), ('__dict__', '__weakref__',))
70+
self.assertEqual(tuple(DWR().__slots__), ('__dict__', '__weakref__',))
71+
72+
def test_dict_if_slots(self):
73+
class C: __slots__ = ['a']
74+
self.assertEqual(tuple(C.__dict__['__slots__']), ('a',))
75+
76+
def test_slots_are_not_sorted(self):
77+
class C: __slots__ = ['b', 'a']
78+
self.assertEqual(tuple(C.__slots__), ('b', 'a',))
79+
80+
def test_forbidden_slot_names(self):
81+
raised = False
82+
try:
83+
class C:
84+
__slots__ = ['__slots__']
85+
except ValueError:
86+
raised = True
87+
assert raised
88+
89+
raised = False
90+
try:
91+
class C:
92+
v = 1
93+
__slots__ = ['v']
94+
except ValueError:
95+
raised = True
96+
assert raised
97+
6098
if __name__ == "__main__":
6199
unittest.main()

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,19 +2341,28 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
23412341
// have slots
23422342

23432343
// Make it into a list
2344-
SequenceStorage slotList;
2344+
SequenceStorage slotsStorage;
2345+
Object slotsObject;
23452346
if (slots instanceof String) {
2346-
slotList = factory().createList(new Object[]{slots}).getSequenceStorage();
2347+
slotsObject = factory().createList(new Object[]{slots});
2348+
slotsStorage = ((PList) slotsObject).getSequenceStorage();
2349+
} else if (slots instanceof PTuple) {
2350+
slotsObject = slots;
2351+
slotsStorage = ((PTuple) slots).getSequenceStorage();
2352+
} else if (slots instanceof PList) {
2353+
slotsObject = slots;
2354+
slotsStorage = ((PList) slots).getSequenceStorage();
23472355
} else {
2348-
slotList = getCastToListNode().execute(frame, slots).getSequenceStorage();
2356+
slotsObject = getCastToListNode().execute(frame, slots);
2357+
slotsStorage = ((PList) slotsObject).getSequenceStorage();
23492358
}
2350-
int slotlen = getListLenNode().execute(slotList);
2359+
int slotlen = getListLenNode().execute(slotsStorage);
23512360
// TODO: tfel - check if slots are allowed. They are not if the base class is var
23522361
// sized
23532362

23542363
for (int i = 0; i < slotlen; i++) {
23552364
String slotName;
2356-
Object element = getSlotItemNode().execute(frame, slotList, i);
2365+
Object element = getSlotItemNode().execute(frame, slotsStorage, i);
23572366
// Check valid slot name
23582367
if (element instanceof String) {
23592368
slotName = (String) element;
@@ -2378,13 +2387,15 @@ private PythonClass typeMetaclass(VirtualFrame frame, String name, PTuple bases,
23782387
PythonContext context = getContextRef().get();
23792388
Object state = ForeignCallContext.enter(frame, context, this);
23802389
try {
2381-
PTuple newSlots = copySlots(name, slotList, slotlen, addDict, false, namespace, nslib);
2382-
pythonClass.setAttribute(__SLOTS__, newSlots);
2390+
pythonClass.setAttribute(__SLOTS__, slotsObject);
23832391
if (basesArray.length > 1) {
23842392
// TODO: tfel - check if secondary bases provide weakref or dict when we
23852393
// don't already have one
23862394
}
23872395

2396+
// checks for some name errors too
2397+
PTuple newSlots = copySlots(name, slotsStorage, slotlen, addDict, false, namespace, nslib);
2398+
23882399
// add native slot descriptors
23892400
if (pythonClass.needsNativeAllocation()) {
23902401
addNativeSlots(pythonClass, newSlots);

0 commit comments

Comments
 (0)