Commit 105cf92d authored by Stefan Behnel's avatar Stefan Behnel

Merge branch '0.29.x'

parents 016762d1 888bc4a4
...@@ -178,6 +178,9 @@ Other changes ...@@ -178,6 +178,9 @@ Other changes
* Double reference free in ``__class__`` cell handling for ``super()`` calls. * Double reference free in ``__class__`` cell handling for ``super()`` calls.
(Github issue #3246) (Github issue #3246)
* Compile error when using ``*args`` as Python class bases.
(Github issue #3338)
* Import failure in IPython 7.11. * Import failure in IPython 7.11.
(Github issue #3297) (Github issue #3297)
......
...@@ -8914,12 +8914,11 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -8914,12 +8914,11 @@ class ClassNode(ExprNode, ModuleNameMixin):
# a name, tuple of bases and class dictionary. # a name, tuple of bases and class dictionary.
# #
# name EncodedString Name of the class # name EncodedString Name of the class
# bases ExprNode Base class tuple # class_def_node PyClassDefNode PyClassDefNode defining this class
# dict ExprNode Class dict (not owned by this node)
# doc ExprNode or None Doc string # doc ExprNode or None Doc string
# module_name EncodedString Name of defining module # module_name EncodedString Name of defining module
subexprs = ['bases', 'doc'] subexprs = ['doc']
type = py_object_type type = py_object_type
is_temp = True is_temp = True
...@@ -8928,7 +8927,6 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -8928,7 +8927,6 @@ class ClassNode(ExprNode, ModuleNameMixin):
return py_object_type return py_object_type
def analyse_types(self, env): def analyse_types(self, env):
self.bases = self.bases.analyse_types(env)
if self.doc: if self.doc:
self.doc = self.doc.analyse_types(env) self.doc = self.doc.analyse_types(env)
self.doc = self.doc.coerce_to_pyobject(env) self.doc = self.doc.coerce_to_pyobject(env)
...@@ -8941,12 +8939,13 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -8941,12 +8939,13 @@ class ClassNode(ExprNode, ModuleNameMixin):
gil_message = "Constructing Python class" gil_message = "Constructing Python class"
def generate_result_code(self, code): def generate_result_code(self, code):
class_def_node = self.class_def_node
cname = code.intern_identifier(self.name) cname = code.intern_identifier(self.name)
if self.doc: if self.doc:
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
'PyDict_SetItem(%s, %s, %s)' % ( 'PyDict_SetItem(%s, %s, %s)' % (
self.dict.py_result(), class_def_node.dict.py_result(),
code.intern_identifier( code.intern_identifier(
StringEncoding.EncodedString("__doc__")), StringEncoding.EncodedString("__doc__")),
self.doc.py_result())) self.doc.py_result()))
...@@ -8955,8 +8954,8 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -8955,8 +8954,8 @@ class ClassNode(ExprNode, ModuleNameMixin):
code.putln( code.putln(
'%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % ( '%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % (
self.result(), self.result(),
self.bases.py_result(), class_def_node.bases.py_result(),
self.dict.py_result(), class_def_node.dict.py_result(),
cname, cname,
qualname, qualname,
py_mod_name, py_mod_name,
...@@ -8970,8 +8969,8 @@ class Py3ClassNode(ExprNode): ...@@ -8970,8 +8969,8 @@ class Py3ClassNode(ExprNode):
# a name, tuple of bases and class dictionary. # a name, tuple of bases and class dictionary.
# #
# name EncodedString Name of the class # name EncodedString Name of the class
# dict ExprNode Class dict (not owned by this node)
# module_name EncodedString Name of defining module # module_name EncodedString Name of defining module
# class_def_node PyClassDefNode PyClassDefNode defining this class
# calculate_metaclass bool should call CalculateMetaclass() # calculate_metaclass bool should call CalculateMetaclass()
# allow_py2_metaclass bool should look for Py2 metaclass # allow_py2_metaclass bool should look for Py2 metaclass
...@@ -8994,12 +8993,10 @@ class Py3ClassNode(ExprNode): ...@@ -8994,12 +8993,10 @@ class Py3ClassNode(ExprNode):
def generate_result_code(self, code): def generate_result_code(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("Py3ClassCreate", "ObjectHandling.c")) code.globalstate.use_utility_code(UtilityCode.load_cached("Py3ClassCreate", "ObjectHandling.c"))
cname = code.intern_identifier(self.name) cname = code.intern_identifier(self.name)
if self.mkw: class_def_node = self.class_def_node
mkw = self.mkw.py_result() mkw = class_def_node.mkw.py_result() if class_def_node.mkw else 'NULL'
else: if class_def_node.metaclass:
mkw = 'NULL' metaclass = class_def_node.metaclass.py_result()
if self.metaclass:
metaclass = self.metaclass.py_result()
else: else:
metaclass = "((PyObject*)&__Pyx_DefaultClassType)" metaclass = "((PyObject*)&__Pyx_DefaultClassType)"
code.putln( code.putln(
...@@ -9007,8 +9004,8 @@ class Py3ClassNode(ExprNode): ...@@ -9007,8 +9004,8 @@ class Py3ClassNode(ExprNode):
self.result(), self.result(),
metaclass, metaclass,
cname, cname,
self.bases.py_result(), class_def_node.bases.py_result(),
self.dict.py_result(), class_def_node.dict.py_result(),
mkw, mkw,
self.calculate_metaclass, self.calculate_metaclass,
self.allow_py2_metaclass, self.allow_py2_metaclass,
...@@ -9019,8 +9016,7 @@ class Py3ClassNode(ExprNode): ...@@ -9019,8 +9016,7 @@ class Py3ClassNode(ExprNode):
class PyClassMetaclassNode(ExprNode): class PyClassMetaclassNode(ExprNode):
# Helper class holds Python3 metaclass object # Helper class holds Python3 metaclass object
# #
# bases ExprNode Base class tuple (not owned by this node) # class_def_node PyClassDefNode PyClassDefNode defining this class
# mkw ExprNode Class keyword arguments (not owned by this node)
subexprs = [] subexprs = []
...@@ -9033,38 +9029,38 @@ class PyClassMetaclassNode(ExprNode): ...@@ -9033,38 +9029,38 @@ class PyClassMetaclassNode(ExprNode):
return True return True
def generate_result_code(self, code): def generate_result_code(self, code):
if self.mkw: bases = self.class_def_node.bases
mkw = self.class_def_node.mkw
if mkw:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
UtilityCode.load_cached("Py3MetaclassGet", "ObjectHandling.c")) UtilityCode.load_cached("Py3MetaclassGet", "ObjectHandling.c"))
call = "__Pyx_Py3MetaclassGet(%s, %s)" % ( call = "__Pyx_Py3MetaclassGet(%s, %s)" % (
self.bases.result(), bases.result(),
self.mkw.result()) mkw.result())
else: else:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
UtilityCode.load_cached("CalculateMetaclass", "ObjectHandling.c")) UtilityCode.load_cached("CalculateMetaclass", "ObjectHandling.c"))
call = "__Pyx_CalculateMetaclass(NULL, %s)" % ( call = "__Pyx_CalculateMetaclass(NULL, %s)" % (
self.bases.result()) bases.result())
code.putln( code.putln(
"%s = %s; %s" % ( "%s = %s; %s" % (
self.result(), call, self.result(), call,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class PyClassNamespaceNode(ExprNode, ModuleNameMixin): class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
# Helper class holds Python3 namespace object # Helper class holds Python3 namespace object
# #
# All this are not owned by this node # All this are not owned by this node
# metaclass ExprNode Metaclass object # class_def_node PyClassDefNode PyClassDefNode defining this class
# bases ExprNode Base class tuple
# mkw ExprNode Class keyword arguments
# doc ExprNode or None Doc string (owned) # doc ExprNode or None Doc string (owned)
subexprs = ['doc'] subexprs = ['doc']
def analyse_types(self, env): def analyse_types(self, env):
if self.doc: if self.doc:
self.doc = self.doc.analyse_types(env) self.doc = self.doc.analyse_types(env).coerce_to_pyobject(env)
self.doc = self.doc.coerce_to_pyobject(env)
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
return self return self
...@@ -9076,23 +9072,16 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin): ...@@ -9076,23 +9072,16 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
cname = code.intern_identifier(self.name) cname = code.intern_identifier(self.name)
py_mod_name = self.get_py_mod_name(code) py_mod_name = self.get_py_mod_name(code)
qualname = self.get_py_qualified_name(code) qualname = self.get_py_qualified_name(code)
if self.doc: class_def_node = self.class_def_node
doc_code = self.doc.result() null = "(PyObject *) NULL"
else: doc_code = self.doc.result() if self.doc else null
doc_code = '(PyObject *) NULL' mkw = class_def_node.mkw.py_result() if class_def_node.mkw else null
if self.mkw: metaclass = class_def_node.metaclass.py_result() if class_def_node.metaclass else null
mkw = self.mkw.py_result()
else:
mkw = '(PyObject *) NULL'
if self.metaclass:
metaclass = self.metaclass.py_result()
else:
metaclass = "(PyObject *) NULL"
code.putln( code.putln(
"%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s, %s); %s" % ( "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s, %s); %s" % (
self.result(), self.result(),
metaclass, metaclass,
self.bases.result(), class_def_node.bases.result(),
cname, cname,
qualname, qualname,
mkw, mkw,
......
...@@ -4675,26 +4675,22 @@ class PyClassDefNode(ClassDefNode): ...@@ -4675,26 +4675,22 @@ class PyClassDefNode(ClassDefNode):
pass # no base classes => no inherited metaclass pass # no base classes => no inherited metaclass
else: else:
self.metaclass = ExprNodes.PyClassMetaclassNode( self.metaclass = ExprNodes.PyClassMetaclassNode(
pos, mkw=mkdict, bases=self.bases) pos, class_def_node=self)
needs_metaclass_calculation = False needs_metaclass_calculation = False
else: else:
needs_metaclass_calculation = True needs_metaclass_calculation = True
self.dict = ExprNodes.PyClassNamespaceNode( self.dict = ExprNodes.PyClassNamespaceNode(
pos, name=name, doc=doc_node, pos, name=name, doc=doc_node, class_def_node=self)
metaclass=self.metaclass, bases=self.bases, mkw=self.mkw)
self.classobj = ExprNodes.Py3ClassNode( self.classobj = ExprNodes.Py3ClassNode(
pos, name=name, pos, name=name, class_def_node=self, doc=doc_node,
bases=self.bases, dict=self.dict, doc=doc_node,
metaclass=self.metaclass, mkw=self.mkw,
calculate_metaclass=needs_metaclass_calculation, calculate_metaclass=needs_metaclass_calculation,
allow_py2_metaclass=allow_py2_metaclass) allow_py2_metaclass=allow_py2_metaclass)
else: else:
# no bases, no metaclass => old style class creation # no bases, no metaclass => old style class creation
self.dict = ExprNodes.DictNode(pos, key_value_pairs=[]) self.dict = ExprNodes.DictNode(pos, key_value_pairs=[])
self.classobj = ExprNodes.ClassNode( self.classobj = ExprNodes.ClassNode(
pos, name=name, pos, name=name, class_def_node=self, doc=doc_node)
bases=bases, dict=self.dict, doc=doc_node)
self.target = ExprNodes.NameNode(pos, name=name) self.target = ExprNodes.NameNode(pos, name=name)
self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos) self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos)
...@@ -4712,7 +4708,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -4712,7 +4708,7 @@ class PyClassDefNode(ClassDefNode):
visibility='private', visibility='private',
module_name=None, module_name=None,
class_name=self.name, class_name=self.name,
bases=self.classobj.bases or ExprNodes.TupleNode(self.pos, args=[]), bases=self.bases or ExprNodes.TupleNode(self.pos, args=[]),
decorators=self.decorators, decorators=self.decorators,
body=self.body, body=self.body,
in_pxd=False, in_pxd=False,
...@@ -4736,6 +4732,10 @@ class PyClassDefNode(ClassDefNode): ...@@ -4736,6 +4732,10 @@ class PyClassDefNode(ClassDefNode):
args=[class_result]) args=[class_result])
self.decorators = None self.decorators = None
self.class_result = class_result self.class_result = class_result
if self.bases:
self.bases.analyse_declarations(env)
if self.mkw:
self.mkw.analyse_declarations(env)
self.class_result.analyse_declarations(env) self.class_result.analyse_declarations(env)
self.target.analyse_target_declaration(env) self.target.analyse_target_declaration(env)
cenv = self.create_scope(env) cenv = self.create_scope(env)
...@@ -4748,10 +4748,10 @@ class PyClassDefNode(ClassDefNode): ...@@ -4748,10 +4748,10 @@ class PyClassDefNode(ClassDefNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
if self.bases: if self.bases:
self.bases = self.bases.analyse_expressions(env) self.bases = self.bases.analyse_expressions(env)
if self.metaclass:
self.metaclass = self.metaclass.analyse_expressions(env)
if self.mkw: if self.mkw:
self.mkw = self.mkw.analyse_expressions(env) self.mkw = self.mkw.analyse_expressions(env)
if self.metaclass:
self.metaclass = self.metaclass.analyse_expressions(env)
self.dict = self.dict.analyse_expressions(env) self.dict = self.dict.analyse_expressions(env)
self.class_result = self.class_result.analyse_expressions(env) self.class_result = self.class_result.analyse_expressions(env)
cenv = self.scope cenv = self.scope
......
...@@ -24,3 +24,22 @@ def cond_if_bases(x): ...@@ -24,3 +24,22 @@ def cond_if_bases(x):
class PyClass(A if x else B): class PyClass(A if x else B):
p = 5 p = 5
return PyClass return PyClass
def make_subclass(*bases):
"""
>>> cls = make_subclass(list)
>>> issubclass(cls, list) or cls.__mro__
True
>>> class Cls(object): pass
>>> cls = make_subclass(Cls, list)
>>> issubclass(cls, list) or cls.__mro__
True
>>> issubclass(cls, Cls) or cls.__mro__
True
"""
# GH-3338
class MadeClass(*bases):
pass
return MadeClass
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment