Issue2551

classification
Title: __slots__ in diamond-style causes lay-out conflict (breaks pathlib and sympy)
Type: behaviour Severity: normal
Components: Core Versions: Jython 2.7
Milestone: Jython 2.7.1
process
Status: pending Resolution: fixed
Dependencies: Superseder:
Assigned To: stefan.richthofer Nosy List: asmeurer, stefan.richthofer
Priority: normal Keywords:

Created on 2017-02-08.16:08:40 by stefan.richthofer, last changed 2017-02-08.22:25:48 by stefan.richthofer.

Messages
msg11085 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-08.16:08:39
#2475 and #1777 both suffer the issue that Jython emits

TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

under certain __slot__ usage. While in #1777 it was suggested to simply avoid using __slots__ in Jython, which is actually a suitable workaround as proposed in https://github.com/sympy/sympy/pull/12120, that hint stems from a time when Jython had no __slots__ support at all.
Given that this issue also occurs elsewhere and nowadays __slots__ is actually supported in Jython we might better get this fixed. In case this issue turns out to be fixable with some reasonable effort I would withdraw https://github.com/sympy/sympy/pull/12120 in favor of a Jython-side solution.

I undertook the effort to boil it down to following diamond-style configuration:

class test1(object):
    __slots__ = ('a',)

class test2_1(test1):
    __slots__ = ()

class test2_2(test1):
    __slots__ = ()

class test3(test2_1, test2_2):
    pass


which fails in Jython, but passes in CPython.
Same behavior if either test2_1 or test2_2 have some value in __slots__, e.g. ('b') or also ('a') (name seems not to matter).

On the other hand if test2_1 and test2_2 both have some value in __slots__, e.g. ('b'), ('c') (but same with ('a'), ('a') or so, name doesn't matter here either) this fails in CPython too with the same error.

This issue might or might not be related to #2101 / #1996, cannot tell yet.
msg11086 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-08.16:20:05
This issue looks like a variant of what is tested in

test_class_jy / test_slotted_diamond_problem_bug

So a similar but not totally equal issue was already discovered an fixed once upon a time.
msg11089 (view) Author: Aaron Meurer (asmeurer) Date: 2017-02-08.17:22:20
From what I can tell based on the documentation, this should work https://docs.python.org/3.6/reference/datamodel.html#slots.
msg11090 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-08.21:46:02
After some digging I'm convinced the problem lies in PyType and is about detection of what is called a solid base. I.e. a class defining __slots__ = () shall actually not be considered a solid base, but currently is. A proper solid base would have to actually add a slot, not set slots to an empty sequence. Solid bases are detected based on numSlots, which would normally be 0 if slots is an empty sequence. However in the example numSlots would be 1 because of the parent class.

I would modify

private static boolean isSolidBase(PyType type) {
        return type.underlying_class != null || (type.numSlots != 0 && !type.needs_userdict);
}

such that it doesn't rely on absolute numSlots value but on the difference to base's numSlots. So to be a solid base it must actually *introduce* a slot, not just *have* a slot from base or so.

Proposed change:

private static boolean isSolidBase(PyType type) {
    return type.underlying_class != null || (type.numSlots - (type.base != null ? type.base.numSlots : 0) != 0 && !type.needs_userdict);
}
msg11091 (view) Author: Stefan Richthofer (stefan.richthofer) Date: 2017-02-08.22:25:48
Fixed as of https://github.com/jythontools/jython/commit/d9908177c85218f26bcdad1f698127a7d5bfb3d9
History
Date User Action Args
2017-02-08 22:25:48stefan.richthofersetstatus: open -> pending
assignee: stefan.richthofer
resolution: fixed
messages: + msg11091
milestone: Jython 2.7.1
2017-02-08 21:46:02stefan.richthofersetmessages: + msg11090
title: __slots__ in Diamond-style causes lay-out conflict (breaks pathlib and sympy) -> __slots__ in diamond-style causes lay-out conflict (breaks pathlib and sympy)
2017-02-08 17:22:20asmeurersetmessages: + msg11089
2017-02-08 16:20:05stefan.richthofersetmessages: + msg11086
2017-02-08 16:08:40stefan.richthofercreate