summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2020-04-15 19:34:39 +0100
committerGitHub <noreply@github.com>2020-04-15 20:34:39 +0200
commit192925d8800421a791a783307118246b9c3d922f (patch)
tree79d043253a6b7270875bef7567997dcf400066c9
parentc1f3fd2831083b675acd6b0ee73dddcec5671d31 (diff)
downloadcython-192925d8800421a791a783307118246b9c3d922f.tar.gz
Prevent fused dispatcher optional arguments being overwritten (GH-3519)
* Prevent fused dispatcher optional arguments being overwritten If the 5th argument of the regular functions was optional it'd overwrite the _fused_sigindex default of the dispatcher, causing type errors at runtime. closes https://github.com/cython/cython/issues/3511
-rw-r--r--Cython/Compiler/ExprNodes.py22
-rw-r--r--Cython/Compiler/FusedNode.py3
-rw-r--r--tests/run/fused_def.pyx18
3 files changed, 26 insertions, 17 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 187187af5..1ad7a3ad2 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -9449,15 +9449,19 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if self.defaults_tuple:
code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % (
self.result(), self.defaults_tuple.py_result()))
- if self.defaults_kwdict:
- code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % (
- self.result(), self.defaults_kwdict.py_result()))
- if def_node.defaults_getter:
- code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
- self.result(), def_node.defaults_getter.entry.pyfunc_cname))
- if self.annotations_dict:
- code.putln('__Pyx_CyFunction_SetAnnotationsDict(%s, %s);' % (
- self.result(), self.annotations_dict.py_result()))
+ if not self.specialized_cpdefs:
+ # disable introspection functions for fused dispatcher function since the user never sees it
+ # TODO: this is mostly disabled because the attributes end up pointing to ones belonging
+ # to the specializations - ideally this would be fixed instead
+ if self.defaults_kwdict:
+ code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % (
+ self.result(), self.defaults_kwdict.py_result()))
+ if def_node.defaults_getter:
+ code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
+ self.result(), def_node.defaults_getter.entry.pyfunc_cname))
+ if self.annotations_dict:
+ code.putln('__Pyx_CyFunction_SetAnnotationsDict(%s, %s);' % (
+ self.result(), self.annotations_dict.py_result()))
class InnerFunctionNode(PyCFunctionNode):
diff --git a/Cython/Compiler/FusedNode.py b/Cython/Compiler/FusedNode.py
index 456103a5e..0072174c3 100644
--- a/Cython/Compiler/FusedNode.py
+++ b/Cython/Compiler/FusedNode.py
@@ -839,7 +839,8 @@ class FusedCFuncDefNode(StatListNode):
for i, stat in enumerate(self.stats):
stat = self.stats[i] = stat.analyse_expressions(env)
- if isinstance(stat, FuncDefNode):
+ if isinstance(stat, FuncDefNode) and stat is not self.py_func:
+ # the dispatcher specifically doesn't want its defaults overriding
for arg, default in zip(stat.args, defaults):
if default is not None:
arg.default = CloneNode(default).coerce_to(arg.type, env)
diff --git a/tests/run/fused_def.pyx b/tests/run/fused_def.pyx
index f0e1be4c8..efd578298 100644
--- a/tests/run/fused_def.pyx
+++ b/tests/run/fused_def.pyx
@@ -54,9 +54,13 @@ f = 5.6
i = 9
-def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7):
+def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7,
+ another_opt = 2, yet_another_opt=3):
"""
- Test runtime dispatch, indexing of various kinds and optional arguments
+ Test runtime dispatch, indexing of various kinds and optional arguments.
+ Use 5 arguments because at one point the optional argument from the
+ 5th argument was overwriting that of the __pyx_fused dispatcher.
+ https://github.com/cython/cython/issues/3511
>>> opt_func("spam", f, i)
str object double long
@@ -121,9 +125,9 @@ def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7):
>>> opt_func()
Traceback (most recent call last):
TypeError: Expected at least 1 argument, got 0
- >>> opt_func("abc", f, i, 5) # doctest: +ELLIPSIS
+ >>> opt_func("abc", f, i, 5, 5, 5) # doctest: +ELLIPSIS
Traceback (most recent call last):
- TypeError: ...at most 3...
+ TypeError: ...at most 5...
>>> opt_func[ExtClassA, cy.float, cy.long](object(), f)
Traceback (most recent call last):
TypeError: Argument 'obj' has incorrect type (expected fused_def.ExtClassA, got object)
@@ -154,19 +158,19 @@ def test_opt_func():
def test_opt_func_introspection():
"""
>>> opt_func.__defaults__
- (1.2, 7)
+ (1.2, 7, 2, 3)
>>> opt_func.__kwdefaults__
>>> opt_func.__annotations__
{}
>>> opt_func[str, float, int].__defaults__
- (1.2, 7)
+ (1.2, 7, 2, 3)
>>> opt_func[str, float, int].__kwdefaults__
>>> opt_func[str, float, int].__annotations__
{}
>>> opt_func[str, cy.double, cy.long].__defaults__
- (1.2, 7)
+ (1.2, 7, 2, 3)
>>> opt_func[str, cy.double, cy.long].__kwdefaults__
>>> opt_func[str, cy.double, cy.long].__annotations__
{}