diff --git a/CHANGES.current b/CHANGES.current index 67afee72c..d73925dbb 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,9 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.0.0 (in progress) =========================== +2018-09-19: wsfulton + [Python] Fix functors (wrapped as __call__) when using -builtin -modern -fastunpack. + 2018-09-02: andreas.gaeer,tkrasnukha [Python] #1321 Fix assert in PyTuple_GET_SIZE in debug interpreter builds of python-3.7 when calling tp_new. diff --git a/Examples/test-suite/functors.i b/Examples/test-suite/functors.i new file mode 100644 index 000000000..363123000 --- /dev/null +++ b/Examples/test-suite/functors.i @@ -0,0 +1,33 @@ +%module functors + +// Rename operator() only if the language does not already do this by default +#if defined(SWIGCSHARP) || defined(SWIGGO) || defined(SWIGGUILE) || defined(SWIGJAVA) || defined(SWIGJAVASCRIPT) || defined(SWIGPHP) || defined(SWIGSCILAB) || defined(SWIGTCL) +%rename(Funktor) operator(); +#endif + +%inline %{ +class Functor0 { + int num; +public: + Functor0(int num) : num(num) {} + int operator()() { return -num; } + int operate() { return this->operator()(); } +}; + +class Functor1 { + int num; +public: + Functor1(int num) : num(num) {} + int operator()(int x) { return num + x; } + int operate(int x) { return this->operator()(x); } +}; + +class Functor2 { + int num; +public: + Functor2(int num) : num(num) {} + int operator()(int x, int x2) { return num + x + x2; } + int operate(int x, int x2) { return this->operator()(x, x2); } +}; +%} + diff --git a/Examples/test-suite/python/functors_runme.py b/Examples/test-suite/python/functors_runme.py new file mode 100644 index 000000000..98945a047 --- /dev/null +++ b/Examples/test-suite/python/functors_runme.py @@ -0,0 +1,12 @@ +from functors import * + +a = Functor0(10) +b = Functor1(10) +c = Functor2(10) + +if a()!=-10: + raise RuntimeError("a failed") +if b(1)!=11: + raise RuntimeError("b failed") +if c(1, 2)!=13: + raise RuntimeError("c failed") diff --git a/Examples/test-suite/python/operator_overload_runme.py b/Examples/test-suite/python/operator_overload_runme.py index cf4277f35..31c49058e 100644 --- a/Examples/test-suite/python/operator_overload_runme.py +++ b/Examples/test-suite/python/operator_overload_runme.py @@ -75,3 +75,10 @@ if not -a==a: if not -b==Op(-5): raise RuntimeError("-b==Op(-5)") +# test functors +if not b()==5: + raise RuntimeError("functor") +if not b(1)==6: + raise RuntimeError("functor") +if not b(1, 2)==8: + raise RuntimeError("functor") diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 9861ddee6..90e8b0b44 100755 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -3020,8 +3020,9 @@ public: } Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); } else { + int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call"); Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); - if (onearg && !builtin_ctor) { + if (onearg && !builtin_ctor && !is_tp_call) { Printf(parse_args, "if (!args) SWIG_fail;\n"); Append(parse_args, "swig_obj[0] = args;\n"); } else if (!noargs) {