Commit 5c1338cb authored by Vitja Makarov's avatar Vitja Makarov

Merge pull request #70 from markflorisson88/fusedsuper

Fused classmethods & staticmethods & super
parents 60be9a7b 2ddb5478
...@@ -5766,6 +5766,59 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin): ...@@ -5766,6 +5766,59 @@ class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
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 ClassCellInjectorNode(ExprNode):
# Initialize CyFunction.func_classobj
is_temp = True
type = py_object_type
subexprs = []
is_active = False
def analyse_expressions(self, env):
if self.is_active:
env.use_utility_code(cyfunction_class_cell_utility_code)
def generate_evaluation_code(self, code):
if self.is_active:
self.allocate_temp_result(code)
code.putln(
'%s = PyList_New(0); %s' % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result())
def generate_injection_code(self, code, classobj_cname):
if self.is_active:
code.putln('__Pyx_CyFunction_InitClassCell(%s, %s);' % (
self.result(), classobj_cname))
class ClassCellNode(ExprNode):
# Class Cell for noargs super()
subexprs = []
is_temp = True
is_generator = False
type = py_object_type
def analyse_types(self, env):
pass
def generate_result_code(self, code):
if not self.is_generator:
code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
self.result(),
Naming.self_cname))
else:
code.putln('%s = %s->classobj;' % (
self.result(), Naming.cur_scope_cname))
code.putln(
'if (!%s) { PyErr_SetString(PyExc_SystemError, '
'"super(): empty __class__ cell"); %s }' % (
self.result(),
code.error_goto(self.pos)));
code.put_incref(self.result(), py_object_type)
class BoundMethodNode(ExprNode): class BoundMethodNode(ExprNode):
# Helper class used in the implementation of Python # Helper class used in the implementation of Python
# class definitions. Constructs an bound method # class definitions. Constructs an bound method
...@@ -5832,6 +5885,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5832,6 +5885,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
# pymethdef_cname string PyMethodDef structure # pymethdef_cname string PyMethodDef structure
# self_object ExprNode or None # self_object ExprNode or None
# binding bool # binding bool
# def_node DefNode the Python function node
# module_name EncodedString Name of defining module # module_name EncodedString Name of defining module
# code_object CodeObjectNode the PyCodeObject creator node # code_object CodeObjectNode the PyCodeObject creator node
...@@ -5840,6 +5894,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5840,6 +5894,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
self_object = None self_object = None
code_object = None code_object = None
binding = False binding = False
def_node = None
type = py_object_type type = py_object_type
is_temp = 1 is_temp = 1
...@@ -5873,25 +5928,52 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5873,25 +5928,52 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
def generate_result_code(self, code): def generate_result_code(self, code):
if self.binding: if self.binding:
if self.specialized_cpdefs: self.generate_cyfunction_code(code)
constructor = "__pyx_FusedFunction_NewEx" else:
else: self.generate_pycfunction_code(code)
constructor = "__Pyx_CyFunction_NewEx"
if self.code_object: def generate_pycfunction_code(self, code):
code_object_result = ', ' + self.code_object.py_result() py_mod_name = self.get_py_mod_name(code)
else: code.putln(
code_object_result = ', NULL' '%s = PyCFunction_NewEx(&%s, %s, %s); %s' % (
self.result(),
self.pymethdef_cname,
self.self_result_code(),
py_mod_name,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
def generate_cyfunction_code(self, code):
if self.specialized_cpdefs:
constructor = "__pyx_FusedFunction_NewEx"
def_node = self.specialized_cpdefs[0]
else: else:
constructor = "PyCFunction_NewEx" constructor = "__Pyx_CyFunction_NewEx"
code_object_result = '' def_node = self.def_node
if self.code_object:
code_object_result = self.code_object.py_result()
else:
code_object_result = 'NULL'
flags = []
if def_node.is_staticmethod:
flags.append('__Pyx_CYFUNCTION_STATICMETHOD')
elif def_node.is_classmethod:
flags.append('__Pyx_CYFUNCTION_CLASSMETHOD')
if flags:
flags = ' | '.join(flags)
else:
flags = '0'
py_mod_name = self.get_py_mod_name(code) py_mod_name = self.get_py_mod_name(code)
code.putln( code.putln(
'%s = %s(&%s, %s, %s%s); %s' % ( '%s = %s(&%s, %s, %s, %s, %s); %s' % (
self.result(), self.result(),
constructor, constructor,
self.pymethdef_cname, self.pymethdef_cname,
flags,
self.self_result_code(), self.self_result_code(),
py_mod_name, py_mod_name,
code_object_result, code_object_result,
...@@ -5899,10 +5981,20 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5899,10 +5981,20 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
if def_node.requires_classobj:
assert code.pyclass_stack, "pyclass_stack is empty"
class_node = code.pyclass_stack[-1]
code.put_incref(self.py_result(), py_object_type)
code.putln(
'PyList_Append(%s, %s);' % (
class_node.class_cell.result(),
self.result()))
code.put_giveref(self.py_result())
if self.specialized_cpdefs: if self.specialized_cpdefs:
self.generate_fused_cpdef(code, code_object_result) self.generate_fused_cpdef(code, code_object_result, flags)
def generate_fused_cpdef(self, code, code_object_result): def generate_fused_cpdef(self, code, code_object_result, flags):
""" """
Generate binding function objects for all specialized cpdefs, and the Generate binding function objects for all specialized cpdefs, and the
original fused one. The fused function gets a dict __signatures__ original fused one. The fused function gets a dict __signatures__
...@@ -5924,6 +6016,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5924,6 +6016,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
py_mod_name=self.get_py_mod_name(code), py_mod_name=self.get_py_mod_name(code),
self=self.self_result_code(), self=self.self_result_code(),
code=code_object_result, code=code_object_result,
flags=flags,
func=code.funcstate.allocate_temp(py_object_type, func=code.funcstate.allocate_temp(py_object_type,
manage_ref=True), manage_ref=True),
signature=code.funcstate.allocate_temp(py_object_type, signature=code.funcstate.allocate_temp(py_object_type,
...@@ -5945,7 +6038,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin): ...@@ -5945,7 +6038,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
'"%(signature_string)s")') '"%(signature_string)s")')
goto_err("%(func)s = __pyx_FusedFunction_NewEx(" goto_err("%(func)s = __pyx_FusedFunction_NewEx("
"&%(pymethdef_cname)s, %(self)s, %(py_mod_name)s %(code)s)") "&%(pymethdef_cname)s, %(flags)s, %(self)s, %(py_mod_name)s, %(code)s)")
s = "PyDict_SetItem(%(sigdict)s, %(signature)s, %(func)s)" s = "PyDict_SetItem(%(sigdict)s, %(signature)s, %(func)s)"
code.put_error_if_neg(self.pos, s % fmt_dict) code.put_error_if_neg(self.pos, s % fmt_dict)
...@@ -6040,13 +6133,13 @@ class LambdaNode(InnerFunctionNode): ...@@ -6040,13 +6133,13 @@ class LambdaNode(InnerFunctionNode):
child_attrs = ['def_node'] child_attrs = ['def_node']
def_node = None
name = StringEncoding.EncodedString('<lambda>') name = StringEncoding.EncodedString('<lambda>')
def analyse_declarations(self, env): def analyse_declarations(self, env):
self.def_node.no_assignment_synthesis = True self.def_node.no_assignment_synthesis = True
self.def_node.pymethdef_required = True self.def_node.pymethdef_required = True
self.def_node.analyse_declarations(env) self.def_node.analyse_declarations(env)
self.def_node.is_cyfunction = True
self.pymethdef_cname = self.def_node.entry.pymethdef_cname self.pymethdef_cname = self.def_node.entry.pymethdef_cname
env.add_lambda_def(self.def_node) env.add_lambda_def(self.def_node)
...@@ -6074,6 +6167,7 @@ class GeneratorExpressionNode(LambdaNode): ...@@ -6074,6 +6167,7 @@ class GeneratorExpressionNode(LambdaNode):
super(GeneratorExpressionNode, self).analyse_declarations(env) super(GeneratorExpressionNode, self).analyse_declarations(env)
# No pymethdef required # No pymethdef required
self.def_node.pymethdef_required = False self.def_node.pymethdef_required = False
self.def_node.is_cyfunction = False
# Force genexpr signature # Force genexpr signature
self.def_node.entry.signature = TypeSlots.pyfunction_noargs self.def_node.entry.signature = TypeSlots.pyfunction_noargs
...@@ -9858,7 +9952,10 @@ fused_function_utility_code = UtilityCode.load( ...@@ -9858,7 +9952,10 @@ fused_function_utility_code = UtilityCode.load(
"CythonFunction.c", "CythonFunction.c",
context=vars(Naming), context=vars(Naming),
requires=[binding_cfunc_utility_code]) requires=[binding_cfunc_utility_code])
cyfunction_class_cell_utility_code = UtilityCode.load(
"CyFunctionClassCell",
"CythonFunction.c",
requires=[binding_cfunc_utility_code])
generator_utility_code = UtilityCode( generator_utility_code = UtilityCode(
proto=""" proto="""
......
...@@ -1302,6 +1302,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1302,6 +1302,7 @@ class FuncDefNode(StatNode, BlockNode):
has_fused_arguments = False has_fused_arguments = False
star_arg = None star_arg = None
starstar_arg = None starstar_arg = None
is_cyfunction = False
def analyse_default_values(self, env): def analyse_default_values(self, env):
genv = env.global_scope() genv = env.global_scope()
...@@ -1510,10 +1511,16 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1510,10 +1511,16 @@ class FuncDefNode(StatNode, BlockNode):
code.put_gotref(Naming.cur_scope_cname) code.put_gotref(Naming.cur_scope_cname)
# Note that it is unsafe to decref the scope at this point. # Note that it is unsafe to decref the scope at this point.
if self.needs_outer_scope: if self.needs_outer_scope:
code.putln("%s = (%s)%s;" % ( if self.is_cyfunction:
outer_scope_cname, code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % (
cenv.scope_class.type.declaration_code(''), outer_scope_cname,
Naming.self_cname)) cenv.scope_class.type.declaration_code(''),
Naming.self_cname))
else:
code.putln("%s = (%s) %s;" % (
outer_scope_cname,
cenv.scope_class.type.declaration_code(''),
Naming.self_cname))
if lenv.is_passthrough: if lenv.is_passthrough:
code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname)); code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname));
elif self.needs_closure: elif self.needs_closure:
...@@ -2636,6 +2643,7 @@ class DefNode(FuncDefNode): ...@@ -2636,6 +2643,7 @@ class DefNode(FuncDefNode):
acquire_gil = 0 acquire_gil = 0
self_in_stararg = 0 self_in_stararg = 0
py_cfunc_node = None py_cfunc_node = None
requires_classobj = False
doc = None doc = None
fused_py_func = False fused_py_func = False
...@@ -2841,6 +2849,15 @@ class DefNode(FuncDefNode): ...@@ -2841,6 +2849,15 @@ class DefNode(FuncDefNode):
self.self_in_stararg = 1 self.self_in_stararg = 1
nfixed = 0 nfixed = 0
if self.is_staticmethod and env.is_c_class_scope:
nfixed = 0
self.self_in_stararg = True
self.entry.signature = sig = copy.copy(sig)
sig.fixed_arg_format = "*"
sig.is_staticmethod = True
sig.has_generic_args = True
for i in range(min(nfixed, len(self.args))): for i in range(min(nfixed, len(self.args))):
arg = self.args[i] arg = self.args[i]
arg.is_generic = 0 arg.is_generic = 0
...@@ -2977,7 +2994,7 @@ class DefNode(FuncDefNode): ...@@ -2977,7 +2994,7 @@ class DefNode(FuncDefNode):
decorator.decorator.analyse_expressions(env) decorator.decorator.analyse_expressions(env)
def needs_assignment_synthesis(self, env, code=None): def needs_assignment_synthesis(self, env, code=None):
if self.specialized_cpdefs: if self.specialized_cpdefs or self.is_staticmethod:
return True return True
if self.no_assignment_synthesis: if self.no_assignment_synthesis:
return False return False
...@@ -3003,21 +3020,22 @@ class DefNode(FuncDefNode): ...@@ -3003,21 +3020,22 @@ class DefNode(FuncDefNode):
if genv.is_closure_scope: if genv.is_closure_scope:
rhs = self.py_cfunc_node = ExprNodes.InnerFunctionNode( rhs = self.py_cfunc_node = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, self.pos, def_node=self,
code_object = ExprNodes.CodeObjectNode(self)) pymethdef_cname=self.entry.pymethdef_cname,
code_object=ExprNodes.CodeObjectNode(self))
else: else:
rhs = ExprNodes.PyCFunctionNode( rhs = ExprNodes.PyCFunctionNode(
self.pos, self.pos,
pymethdef_cname=self.entry.pymethdef_cname, def_node=self,
binding=env.directives['binding'], pymethdef_cname=self.entry.pymethdef_cname,
specialized_cpdefs=self.specialized_cpdefs, binding=env.directives['binding'],
code_object=ExprNodes.CodeObjectNode(self)) specialized_cpdefs=self.specialized_cpdefs,
code_object=ExprNodes.CodeObjectNode(self))
if env.is_py_class_scope: if env.is_py_class_scope:
if not self.is_staticmethod and not self.is_classmethod: rhs.binding = True
rhs.binding = True
else: self.is_cyfunction = rhs.binding
rhs.binding = False
if self.decorators: if self.decorators:
for decorator in self.decorators[::-1]: for decorator in self.decorators[::-1]:
...@@ -3754,6 +3772,12 @@ class GeneratorDefNode(DefNode): ...@@ -3754,6 +3772,12 @@ class GeneratorDefNode(DefNode):
code.putln('%s.resume_label = 0;' % generator_cname) code.putln('%s.resume_label = 0;' % generator_cname)
code.putln('%s.body = (__pyx_generator_body_t) %s;' % (generator_cname, body_cname)) code.putln('%s.body = (__pyx_generator_body_t) %s;' % (generator_cname, body_cname))
code.put_giveref(Naming.cur_scope_cname) code.put_giveref(Naming.cur_scope_cname)
if self.requires_classobj:
classobj_cname = '%s->classobj' % Naming.cur_scope_cname
code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % (
classobj_cname, Naming.self_cname))
code.put_incref(classobj_cname, py_object_type)
code.put_giveref(classobj_cname)
code.put_finish_refcount_context() code.put_finish_refcount_context()
code.putln("return (PyObject *) %s;" % Naming.cur_scope_cname); code.putln("return (PyObject *) %s;" % Naming.cur_scope_cname);
...@@ -3949,7 +3973,8 @@ class PyClassDefNode(ClassDefNode): ...@@ -3949,7 +3973,8 @@ class PyClassDefNode(ClassDefNode):
# classobj ClassNode Class object # classobj ClassNode Class object
# target NameNode Variable to assign class object to # target NameNode Variable to assign class object to
child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", "target"] child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result",
"target", "class_cell"]
decorators = None decorators = None
class_result = None class_result = None
py3_style_class = False # Python3 style class (bases+kwargs) py3_style_class = False # Python3 style class (bases+kwargs)
...@@ -4006,6 +4031,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -4006,6 +4031,7 @@ class PyClassDefNode(ClassDefNode):
self.classobj = ExprNodes.ClassNode(pos, name = name, self.classobj = ExprNodes.ClassNode(pos, name = name,
bases = bases, dict = self.dict, 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)
def as_cclass(self): def as_cclass(self):
""" """
...@@ -4084,6 +4110,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -4084,6 +4110,7 @@ class PyClassDefNode(ClassDefNode):
cenv = self.scope cenv = self.scope
self.body.analyse_expressions(cenv) self.body.analyse_expressions(cenv)
self.target.analyse_target_expression(env, self.classobj) self.target.analyse_target_expression(env, self.classobj)
self.class_cell.analyse_expressions(cenv)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.generate_lambda_definitions(self.scope, code) self.generate_lambda_definitions(self.scope, code)
...@@ -4098,8 +4125,12 @@ class PyClassDefNode(ClassDefNode): ...@@ -4098,8 +4125,12 @@ class PyClassDefNode(ClassDefNode):
self.metaclass.generate_evaluation_code(code) self.metaclass.generate_evaluation_code(code)
self.dict.generate_evaluation_code(code) self.dict.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.dict.result() cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
self.class_cell.generate_evaluation_code(code)
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
self.class_result.generate_evaluation_code(code) self.class_result.generate_evaluation_code(code)
self.class_cell.generate_injection_code(
code, self.class_result.result())
self.class_cell.generate_disposal_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result() cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
self.target.generate_assignment_code(self.class_result, code) self.target.generate_assignment_code(self.class_result, code)
self.dict.generate_disposal_code(code) self.dict.generate_disposal_code(code)
......
...@@ -2137,6 +2137,12 @@ class CreateClosureClasses(CythonTransform): ...@@ -2137,6 +2137,12 @@ class CreateClosureClasses(CythonTransform):
class_scope = entry.type.scope class_scope = entry.type.scope
class_scope.is_internal = True class_scope.is_internal = True
if node.is_generator and node.requires_classobj:
class_scope.declare_var(pos=node.pos, name='classobj',
cname='classobj',
type=PyrexTypes.py_object_type,
is_cdef=True)
if from_closure: if from_closure:
assert cscope.is_closure_scope assert cscope.is_closure_scope
class_scope.declare_var(pos=node.pos, class_scope.declare_var(pos=node.pos,
...@@ -2411,6 +2417,34 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -2411,6 +2417,34 @@ class TransformBuiltinMethods(EnvTransform):
node.pos, self.current_scope_node(), lenv)) node.pos, self.current_scope_node(), lenv))
return node return node
def _inject_super(self, node, func_name):
lenv = self.current_env()
entry = lenv.lookup_here(func_name)
if entry or node.args:
return node
# Inject no-args super
def_node = self.current_scope_node()
if (not isinstance(def_node, Nodes.DefNode) or not def_node.args or
len(self.env_stack) < 2):
return node
class_node, class_scope = self.env_stack[-2]
if class_scope.is_py_class_scope:
def_node.requires_classobj = True
class_node.class_cell.is_active = True
node.args = [
ExprNodes.ClassCellNode(
node.pos, is_generator=def_node.is_generator),
ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
]
elif class_scope.is_c_class_scope:
node.args = [
ExprNodes.NameNode(
node.pos, name=class_node.scope.name,
entry=class_node.entry),
ExprNodes.NameNode(node.pos, name=def_node.args[0].name)
]
return node
def visit_SimpleCallNode(self, node): def visit_SimpleCallNode(self, node):
# cython.foo # cython.foo
function = node.function.as_cython_attribute() function = node.function.as_cython_attribute()
...@@ -2471,6 +2505,8 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -2471,6 +2505,8 @@ class TransformBuiltinMethods(EnvTransform):
return self._inject_locals(node, func_name) return self._inject_locals(node, func_name)
if func_name == 'eval': if func_name == 'eval':
return self._inject_eval(node, func_name) return self._inject_eval(node, func_name)
if func_name == 'super':
return self._inject_super(node, func_name)
return node return node
......
...@@ -68,6 +68,9 @@ class Signature(object): ...@@ -68,6 +68,9 @@ class Signature(object):
# and are not looked up in here # and are not looked up in here
} }
type_to_format_map = dict([(type_, format_)
for format_, type_ in format_map.iteritems()])
error_value_map = { error_value_map = {
'O': "NULL", 'O': "NULL",
'T': "NULL", 'T': "NULL",
...@@ -91,6 +94,7 @@ class Signature(object): ...@@ -91,6 +94,7 @@ class Signature(object):
self.fixed_arg_format = arg_format self.fixed_arg_format = arg_format
self.ret_format = ret_format self.ret_format = ret_format
self.error_value = self.error_value_map.get(ret_format, None) self.error_value = self.error_value_map.get(ret_format, None)
self.is_staticmethod = False
def num_fixed_args(self): def num_fixed_args(self):
return len(self.fixed_arg_format) return len(self.fixed_arg_format)
...@@ -109,6 +113,11 @@ class Signature(object): ...@@ -109,6 +113,11 @@ class Signature(object):
def return_type(self): def return_type(self):
return self.format_map[self.ret_format] return self.format_map[self.ret_format]
def format_from_type(self, arg_type):
if arg_type.is_pyobject:
arg_type = PyrexTypes.py_object_type
return self.type_to_format_map[arg_type]
def exception_value(self): def exception_value(self):
return self.error_value_map.get(self.ret_format) return self.error_value_map.get(self.ret_format)
...@@ -141,6 +150,9 @@ class Signature(object): ...@@ -141,6 +150,9 @@ class Signature(object):
return [method_noargs] return [method_noargs]
elif full_args in ["OO", "TO"] and not self.has_generic_args: elif full_args in ["OO", "TO"] and not self.has_generic_args:
return [method_onearg] return [method_onearg]
if self.is_staticmethod:
return [method_varargs, method_keywords]
return None return None
......
...@@ -334,6 +334,10 @@ class EnvTransform(CythonTransform): ...@@ -334,6 +334,10 @@ class EnvTransform(CythonTransform):
self.env_stack.pop() self.env_stack.pop()
return node return node
def visit_GeneratorBodyDefNode(self, node):
self.visitchildren(node)
return node
def visit_ClassDefNode(self, node): def visit_ClassDefNode(self, node):
self.env_stack.append((node, node.scope)) self.env_stack.append((node, node.scope))
self.visitchildren(node) self.visitchildren(node)
......
...@@ -4,19 +4,36 @@ ...@@ -4,19 +4,36 @@
#define __Pyx_CyFunction_USED 1 #define __Pyx_CyFunction_USED 1
#include <structmember.h> #include <structmember.h>
#define __Pyx_CYFUNCTION_STATICMETHOD 0x01
#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02
#define __Pyx_CyFunction_GetClosure(f) \
(((__pyx_CyFunctionObject *) (f))->func_closure)
#define __Pyx_CyFunction_GetClassObj(f) \
(((__pyx_CyFunctionObject *) (f))->func_classobj)
typedef struct { typedef struct {
PyCFunctionObject func; PyCFunctionObject func;
int flags;
PyObject *func_dict; PyObject *func_dict;
PyObject *func_weakreflist; PyObject *func_weakreflist;
PyObject *func_name; PyObject *func_name;
PyObject *func_doc; PyObject *func_doc;
PyObject *func_code; PyObject *func_code;
PyObject *func_closure;
PyObject *func_classobj; /* No-args super() class cell */
} __pyx_CyFunctionObject; } __pyx_CyFunctionObject;
static PyTypeObject *__pyx_CyFunctionType = 0; static PyTypeObject *__pyx_CyFunctionType = 0;
#define __Pyx_CyFunction_NewEx(ml, self, module, code) __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, self, module, code) #define __Pyx_CyFunction_NewEx(ml, flags, self, module, code) \
static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml, PyObject *self, PyObject *module, PyObject* code); __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, self, module, code)
static PyObject *__Pyx_CyFunction_New(PyTypeObject *,
PyMethodDef *ml, int flags,
PyObject *self, PyObject *module,
PyObject* code);
static int __Pyx_CyFunction_init(void); static int __Pyx_CyFunction_init(void);
...@@ -93,7 +110,7 @@ __Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure ...@@ -93,7 +110,7 @@ __Pyx_CyFunction_get_self(__pyx_CyFunctionObject *m, CYTHON_UNUSED void *closure
{ {
PyObject *self; PyObject *self;
self = m->func.m_self; self = m->func_closure;
if (self == NULL) if (self == NULL)
self = Py_None; self = Py_None;
Py_INCREF(self); Py_INCREF(self);
...@@ -209,19 +226,23 @@ static PyMethodDef __pyx_CyFunction_methods[] = { ...@@ -209,19 +226,23 @@ static PyMethodDef __pyx_CyFunction_methods[] = {
}; };
static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, PyObject *self, PyObject *module, PyObject* code) { static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags,
PyObject *closure, PyObject *module, PyObject* code) {
__pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type); __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type);
if (op == NULL) if (op == NULL)
return NULL; return NULL;
op->flags = flags;
op->func_weakreflist = NULL; op->func_weakreflist = NULL;
op->func.m_ml = ml; op->func.m_ml = ml;
Py_XINCREF(self); op->func.m_self = (PyObject *) op;
op->func.m_self = self; Py_XINCREF(closure);
op->func_closure = closure;
Py_XINCREF(module); Py_XINCREF(module);
op->func.m_module = module; op->func.m_module = module;
op->func_dict = NULL; op->func_dict = NULL;
op->func_name = NULL; op->func_name = NULL;
op->func_doc = NULL; op->func_doc = NULL;
op->func_classobj = NULL;
Py_XINCREF(code); Py_XINCREF(code);
op->func_code = code; op->func_code = code;
PyObject_GC_Track(op); PyObject_GC_Track(op);
...@@ -231,12 +252,13 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, PyObj ...@@ -231,12 +252,13 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, PyObj
static int static int
__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m)
{ {
Py_CLEAR(m->func.m_self); Py_CLEAR(m->func_closure);
Py_CLEAR(m->func.m_module); Py_CLEAR(m->func.m_module);
Py_CLEAR(m->func_dict); Py_CLEAR(m->func_dict);
Py_CLEAR(m->func_name); Py_CLEAR(m->func_name);
Py_CLEAR(m->func_doc); Py_CLEAR(m->func_doc);
Py_CLEAR(m->func_code); Py_CLEAR(m->func_code);
Py_CLEAR(m->func_classobj);
return 0; return 0;
} }
...@@ -251,17 +273,32 @@ static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) ...@@ -251,17 +273,32 @@ static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m)
static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg)
{ {
Py_VISIT(m->func.m_self); Py_VISIT(m->func_closure);
Py_VISIT(m->func.m_module); Py_VISIT(m->func.m_module);
Py_VISIT(m->func_dict); Py_VISIT(m->func_dict);
Py_VISIT(m->func_name); Py_VISIT(m->func_name);
Py_VISIT(m->func_doc); Py_VISIT(m->func_doc);
Py_VISIT(m->func_code); Py_VISIT(m->func_code);
Py_VISIT(m->func_classobj);
return 0; return 0;
} }
static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type) static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type)
{ {
__pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func;
if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) {
Py_INCREF(func);
return func;
}
if (m->flags & __Pyx_CYFUNCTION_CLASSMETHOD) {
if (type == NULL)
type = (PyObject *)(Py_TYPE(obj));
return PyMethod_New(func,
type, (PyObject *)(Py_TYPE(type)));
}
if (obj == Py_None) if (obj == Py_None)
obj = NULL; obj = NULL;
return PyMethod_New(func, obj, type); return PyMethod_New(func, obj, type);
...@@ -346,7 +383,23 @@ static int __Pyx_CyFunction_init(void) ...@@ -346,7 +383,23 @@ static int __Pyx_CyFunction_init(void)
return 0; return 0;
} }
//////////////////// CyFunctionClassCell.proto ////////////////////
static CYTHON_INLINE void __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions,
PyObject *classobj);
//////////////////// CyFunctionClassCell ////////////////////
void __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions,
PyObject *classobj)
{
int i;
for (i = 0; i < PyList_GET_SIZE(cyfunctions); i++) {
__pyx_CyFunctionObject *m =
(__pyx_CyFunctionObject *) PyList_GET_ITEM(cyfunctions, i);
m->func_classobj = classobj;
Py_INCREF(classobj);
}
}
//////////////////// FusedFunction.proto //////////////////// //////////////////// FusedFunction.proto ////////////////////
typedef struct { typedef struct {
...@@ -356,9 +409,10 @@ typedef struct { ...@@ -356,9 +409,10 @@ typedef struct {
PyObject *self; PyObject *self;
} __pyx_FusedFunctionObject; } __pyx_FusedFunctionObject;
#define __pyx_FusedFunction_NewEx(ml, self, module, code) \ #define __pyx_FusedFunction_NewEx(ml, flags, self, module, code) \
__pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, self, module, code) __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, self, module, code)
static PyObject *__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, static PyObject *__pyx_FusedFunction_New(PyTypeObject *type,
PyMethodDef *ml, int flags,
PyObject *self, PyObject *module, PyObject *self, PyObject *module,
PyObject *code); PyObject *code);
...@@ -369,12 +423,12 @@ static int __pyx_FusedFunction_init(void); ...@@ -369,12 +423,12 @@ static int __pyx_FusedFunction_init(void);
//////////////////// FusedFunction //////////////////// //////////////////// FusedFunction ////////////////////
static PyObject * static PyObject *
__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, PyObject *self, __pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject *self,
PyObject *module, PyObject *code) PyObject *module, PyObject *code)
{ {
__pyx_FusedFunctionObject *fusedfunc = \ __pyx_FusedFunctionObject *fusedfunc =
(__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, self, (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags,
module, code); self, module, code);
if (!fusedfunc) if (!fusedfunc)
return NULL; return NULL;
...@@ -418,7 +472,7 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) ...@@ -418,7 +472,7 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type)
func = (__pyx_FusedFunctionObject *) self; func = (__pyx_FusedFunctionObject *) self;
if (func->self) { if (func->self || func->func.flags & __Pyx_CYFUNCTION_STATICMETHOD) {
/* Do not allow rebinding */ /* Do not allow rebinding */
Py_INCREF(self); Py_INCREF(self);
return self; return self;
...@@ -429,18 +483,25 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) ...@@ -429,18 +483,25 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type)
meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx( meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx(
((PyCFunctionObject *) func)->m_ml, ((PyCFunctionObject *) func)->m_ml,
((PyCFunctionObject *) func)->m_self, ((__pyx_CyFunctionObject *) func)->flags,
((__pyx_CyFunctionObject *) func)->func_closure,
((PyCFunctionObject *) func)->m_module, ((PyCFunctionObject *) func)->m_module,
((__pyx_CyFunctionObject *) func)->func_code); ((__pyx_CyFunctionObject *) func)->func_code);
if (!meth) if (!meth)
return NULL; return NULL;
Py_XINCREF(func->func.func_classobj);
meth->func.func_classobj = func->func.func_classobj;
Py_XINCREF(func->__signatures__); Py_XINCREF(func->__signatures__);
meth->__signatures__ = func->__signatures__; meth->__signatures__ = func->__signatures__;
Py_XINCREF(type); Py_XINCREF(type);
meth->type = type; meth->type = type;
if (func->func.flags & __Pyx_CYFUNCTION_CLASSMETHOD)
obj = type;
Py_XINCREF(obj); Py_XINCREF(obj);
meth->self = obj; meth->self = obj;
...@@ -499,9 +560,16 @@ __pyx_err: ...@@ -499,9 +560,16 @@ __pyx_err:
unbound_result_func = PyObject_GetItem(self->__signatures__, signature); unbound_result_func = PyObject_GetItem(self->__signatures__, signature);
if (unbound_result_func) if (unbound_result_func) {
__pyx_FusedFunctionObject *unbound = (__pyx_FusedFunctionObject *) unbound_result_func;
Py_CLEAR(unbound->func.func_classobj);
Py_XINCREF(self->func.func_classobj);
unbound->func.func_classobj = self->func.func_classobj;
result_func = __pyx_FusedFunction_descr_get(unbound_result_func, result_func = __pyx_FusedFunction_descr_get(unbound_result_func,
self->self, self->type); self->self, self->type);
}
Py_DECREF(signature); Py_DECREF(signature);
Py_XDECREF(unbound_result_func); Py_XDECREF(unbound_result_func);
...@@ -521,11 +589,13 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) ...@@ -521,11 +589,13 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw)
__pyx_FusedFunctionObject *binding_func = (__pyx_FusedFunctionObject *) func; __pyx_FusedFunctionObject *binding_func = (__pyx_FusedFunctionObject *) func;
Py_ssize_t argc = PyTuple_GET_SIZE(args); Py_ssize_t argc = PyTuple_GET_SIZE(args);
PyObject *new_args = NULL; PyObject *new_args = NULL;
PyObject *new_func = NULL; __pyx_FusedFunctionObject *new_func = NULL;
PyObject *result = NULL; PyObject *result = NULL;
PyObject *self = NULL; PyObject *self = NULL;
int is_staticmethod = binding_func->func.flags & __Pyx_CYFUNCTION_STATICMETHOD;
int is_classmethod = binding_func->func.flags & __Pyx_CYFUNCTION_CLASSMETHOD;
if (binding_func->self) { if (binding_func->self && !is_staticmethod) {
/* Bound method call, put 'self' in the args tuple */ /* Bound method call, put 'self' in the args tuple */
Py_ssize_t i; Py_ssize_t i;
new_args = PyTuple_New(argc + 1); new_args = PyTuple_New(argc + 1);
...@@ -543,7 +613,7 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) ...@@ -543,7 +613,7 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw)
} }
args = new_args; args = new_args;
} else if (binding_func->type) { } else if (binding_func->type && !is_staticmethod) {
/* Unbound method call */ /* Unbound method call */
if (argc < 1) { if (argc < 1) {
PyErr_Format(PyExc_TypeError, "Need at least one argument, 0 given."); PyErr_Format(PyExc_TypeError, "Need at least one argument, 0 given.");
...@@ -552,7 +622,8 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) ...@@ -552,7 +622,8 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw)
self = PyTuple_GET_ITEM(args, 0); self = PyTuple_GET_ITEM(args, 0);
} }
if (self && !PyObject_IsInstance(self, binding_func->type)) { if (self && !is_classmethod && !is_staticmethod &&
!PyObject_IsInstance(self, binding_func->type)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"First argument should be of type %s, got %s.", "First argument should be of type %s, got %s.",
((PyTypeObject *) binding_func->type)->tp_name, ((PyTypeObject *) binding_func->type)->tp_name,
...@@ -570,17 +641,23 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw) ...@@ -570,17 +641,23 @@ __pyx_FusedFunction_call(PyObject *func, PyObject *args, PyObject *kw)
if (!tup) if (!tup)
goto __pyx_err; goto __pyx_err;
func = new_func = PyCFunction_Call(func, tup, NULL); new_func = (__pyx_FusedFunctionObject *) PyCFunction_Call(func, tup, NULL);
Py_DECREF(tup); Py_DECREF(tup);
if (!new_func) if (!new_func)
goto __pyx_err; goto __pyx_err;
Py_CLEAR(new_func->func.func_classobj);
Py_XINCREF(binding_func->func.func_classobj);
new_func->func.func_classobj = binding_func->func.func_classobj;
func = (PyObject *) new_func;
} }
result = PyCFunction_Call(func, args, kw); result = PyCFunction_Call(func, args, kw);
__pyx_err: __pyx_err:
Py_XDECREF(new_args); Py_XDECREF(new_args);
Py_XDECREF(new_func); Py_XDECREF((PyObject *) new_func);
return result; return result;
} }
......
...@@ -128,3 +128,106 @@ def args_kwargs(fused_t obj, cython.floating myf = 1.2, *args, **kwargs): ...@@ -128,3 +128,106 @@ def args_kwargs(fused_t obj, cython.floating myf = 1.2, *args, **kwargs):
""" """
print cython.typeof(obj), cython.typeof(myf) print cython.typeof(obj), cython.typeof(myf)
print obj, "%.2f" % myf, "%.2f" % f, args, kwargs print obj, "%.2f" % myf, "%.2f" % f, args, kwargs
class BaseClass(object):
"""
Test fused class/static/normal methods and super() without args
"""
@staticmethod
def mystaticmethod(cython.integral arg1):
print cython.typeof(arg1), arg1
@classmethod
def myclassmethod(cls, cython.integral arg1):
print cls, cython.typeof(arg1), arg1
def normalmethod(self, cython.integral arg1):
print self, cython.typeof(arg1), arg1
def __repr__(self):
return "<%s.%s object>" % (__name__, type(self).__name__)
class SubClass(BaseClass):
@staticmethod
def mystaticmethod(self, cython.integral arg1):
print cython.typeof(arg1), arg1
super().mystaticmethod(arg1 + 1)
@classmethod
def myclassmethod(cls, cython.integral arg1):
print cls, cython.typeof(arg1), arg1
super().myclassmethod(arg1 + 1)
def normalmethod(self, cython.integral arg1):
print self, cython.typeof(arg1), arg1
super().normalmethod(arg1 + 1)
class SubSubClass(SubClass):
pass
def test_fused_def_super():
"""
>>> test_fused_def_super()
long 10
long 11
long 11
long 12
short 12
long 13
short 13
long 14
<class 'fused_def.SubClass'> long 14
<class 'fused_def.SubClass'> long 15
<class 'fused_def.SubClass'> long 15
<class 'fused_def.SubClass'> long 16
<class 'fused_def.SubClass'> short 16
<class 'fused_def.SubClass'> long 17
<class 'fused_def.SubClass'> short 17
<class 'fused_def.SubClass'> long 18
<fused_def.SubClass object> long 18
<fused_def.SubClass object> long 19
<fused_def.SubClass object> long 19
<fused_def.SubClass object> long 20
<fused_def.SubClass object> short 20
<fused_def.SubClass object> long 21
<fused_def.SubClass object> short 21
<fused_def.SubClass object> long 22
"""
obj = SubClass()
cls = SubClass
obj.mystaticmethod(obj, 10)
cls.mystaticmethod(obj, 11)
obj.mystaticmethod[cy.short](obj, 12)
cls.mystaticmethod[cy.short](obj, 13)
obj.myclassmethod(14)
cls.myclassmethod(15)
obj.myclassmethod[cy.short](16)
cls.myclassmethod[cy.short](17)
obj.normalmethod(18)
cls.normalmethod(obj, 19)
obj.normalmethod[cy.short](20)
cls.normalmethod[cy.short](obj, 21)
def test_fused_def_classmethod():
"""
>>> test_fused_def_classmethod()
<class 'fused_def.SubSubClass'> long 10
<class 'fused_def.SubSubClass'> long 11
<class 'fused_def.SubSubClass'> long 11
<class 'fused_def.SubSubClass'> long 12
<class 'fused_def.SubSubClass'> short 12
<class 'fused_def.SubSubClass'> long 13
<class 'fused_def.SubSubClass'> short 13
<class 'fused_def.SubSubClass'> long 14
"""
SubSubClass().myclassmethod(10)
SubSubClass.myclassmethod(11)
SubSubClass().myclassmethod[cy.short](12)
SubSubClass.myclassmethod[cy.short](13)
# mode: run
# tags: py3k_super
class A(object):
def method(self):
return 1
@classmethod
def class_method(cls):
return 2
@staticmethod
def static_method():
return 3
def generator_test(self):
return [1, 2, 3]
class B(A):
"""
>>> obj = B()
>>> obj.method()
1
>>> B.class_method()
2
>>> B.static_method(obj)
3
>>> list(obj.generator_test())
[1, 2, 3]
"""
def method(self):
return super().method()
@classmethod
def class_method(cls):
return super().class_method()
@staticmethod
def static_method(instance):
return super().static_method()
def generator_test(self):
for i in super().generator_test():
yield i
def test_class_cell_empty():
"""
>>> test_class_cell_empty()
Traceback (most recent call last):
...
SystemError: super(): empty __class__ cell
"""
class Base(type):
def __new__(cls, name, bases, attrs):
attrs['foo'](None)
class EmptyClassCell(metaclass=Base):
def foo(self):
super()
cdef class CClassBase(object):
def method(self):
return 1
cdef class CClassSuper(CClassBase):
"""
>>> CClassSuper().method()
1
"""
def method(self):
return super().method()
...@@ -43,3 +43,61 @@ def nested_class(): ...@@ -43,3 +43,61 @@ def nested_class():
def plus1(a): def plus1(a):
return a + 1 return a + 1
return class5 return class5
cdef class BaseClass(object):
"""
Test cdef static methods with super() and Python subclasses
>>> obj = BaseClass()
>>> obj.mystaticmethod(obj, 1)
1
>>> BaseClass.mystaticmethod(obj, 1)
1
>>> obj.mystaticmethod2(1, 2, 3)
1 2 3
>>> BaseClass.mystaticmethod2(1, 2, 3)
1 2 3
"""
@staticmethod
def mystaticmethod(self, arg1):
print arg1
@staticmethod
def mystaticmethod2(a, b, c):
print a, b, c
cdef class SubClass(BaseClass):
"""
>>> obj = SubClass()
>>> obj.mystaticmethod(obj, 1)
1
2
>>> SubClass.mystaticmethod(obj, 1)
1
2
"""
@staticmethod
def mystaticmethod(self, arg1):
print arg1
super().mystaticmethod(self, arg1 + 1)
class SubSubClass(SubClass):
"""
>>> obj = SubSubClass()
>>> obj.mystaticmethod(obj, 1)
1
2
3
>>> SubSubClass.mystaticmethod(obj, 1)
1
2
3
"""
@staticmethod
def mystaticmethod(self, arg1):
print arg1
super().mystaticmethod(self, arg1 + 1)
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