Commit 192925d8 authored by da-woods's avatar da-woods Committed by GitHub

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
parent c1f3fd28
......@@ -9449,6 +9449,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
if self.defaults_tuple:
code.putln('__Pyx_CyFunction_SetDefaultsTuple(%s, %s);' % (
self.result(), self.defaults_tuple.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()))
......
......@@ -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)
......
......@@ -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__
{}
......
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