diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2019-08-06 19:36:14 +0100 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2019-08-06 19:36:14 +0100 |
commit | 86cb3a953230c6c63bf38579a44955b2b5084eaf (patch) | |
tree | fb6c9f957c1d963bbf43b6c16603644997810640 | |
parent | 87bf8ae7aa25bdd024ca7c5f8f4216926393fa3c (diff) | |
download | swig-86cb3a953230c6c63bf38579a44955b2b5084eaf.tar.gz |
Python STL container method overloading fix
Fix method overloading of methods that take STL containers of different types.
Due to some error handling that was not cleared during typehecking.
-rw-r--r-- | CHANGES.current | 50 | ||||
-rw-r--r-- | Examples/test-suite/common.mk | 1 | ||||
-rw-r--r-- | Examples/test-suite/li_std_containers_overload.i | 33 | ||||
-rw-r--r-- | Examples/test-suite/octave/li_std_containers_overload_runme.m | 37 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_containers_overload_runme.py | 29 | ||||
-rw-r--r-- | Examples/test-suite/ruby/li_std_containers_overload_runme.rb | 44 | ||||
-rw-r--r-- | Lib/octave/octcontainer.swg | 10 | ||||
-rw-r--r-- | Lib/python/pycontainer.swg | 10 | ||||
-rw-r--r-- | Lib/ruby/rubycontainer.swg | 10 |
9 files changed, 200 insertions, 24 deletions
diff --git a/CHANGES.current b/CHANGES.current index 6b38059b8..aeef3f57e 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,56 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.0.1 (in progress) =========================== +2019-08-07: wsfulton + [Python] Fix method overloading of methods that take STL containers of different + types. The following usage (using std::vector) would fail when using -builtin: + + %include <std_string.i> + %include <std_vector.i> + + %inline %{ + struct X {}; + %} + + %template(VectorX) std::vector<X>; + %template(VectorInt) std::vector<int>; + + %inline %{ + using namespace std; + string VectorOverload(vector<X> v); + string VectorOverload(vector<int> v); + %} + + The following would incorrectly fail: + + s = VectorOverload([1, 2, 3]) + + With: + + Traceback (most recent call last): + File "runme3.py", line 20, in <module> + ret = VectorOverload([1, 2, 3]) + TypeError: Wrong number or type of arguments for overloaded function 'VectorOverload'. + Possible C/C++ prototypes are: + VectorOverload(std::vector< Number,std::allocator< Number > >) + VectorOverload(std::vector< int,std::allocator< int > >) + + The problem was due to some error handling that was not cleared during typehecking. + In this case an error was not cleared when the elements in the list failed the + typecheck for converting to X. Only occurs in Python 3+. + + In some combinations of overloaded methods, the following type of error message would + occur: + + RuntimeError: in sequence element 0 + + The above exception was the direct cause of the following exception: + + Traceback (most recent call last): + File "runme3.py", line 23, in <module> + check(VectorOverload(v), "vector<X>") + SystemError: <built-in function VectorOverload> returned a result with an error set + 2019-08-01: wsfulton #1602 Fix regression in 4.0.0 where a template function containing a parameter with the same name as the function name led to the parameter name used in the diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 7aa0e91d1..5f7792810 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -643,6 +643,7 @@ CPP_STD_TEST_CASES += \ director_string \ ignore_template_constructor \ li_std_combinations \ + li_std_containers_overload \ li_std_deque \ li_std_except \ li_std_except_as_class \ diff --git a/Examples/test-suite/li_std_containers_overload.i b/Examples/test-suite/li_std_containers_overload.i new file mode 100644 index 000000000..5e7c28e37 --- /dev/null +++ b/Examples/test-suite/li_std_containers_overload.i @@ -0,0 +1,33 @@ +%module li_std_containers_overload + +// Suppress warning that ought not to appear, but there is no easy fix +%warnfilter(SWIGWARN_LANG_OVERLOAD_SHADOW) VectorOverload; + +%include <std_string.i> +%include <std_vector.i> + +%inline %{ +struct X {}; +struct Y {}; +%} + +%template(VectorX) std::vector<X>; +%template(VectorY) std::vector<Y>; +%template(VectorString) std::vector<std::string>; +%template(VectorInt) std::vector<int>; + +%inline %{ +using namespace std; +string VectorOverload(vector<X> v) { + return "vector<X>"; +} +string VectorOverload(vector<Y> v) { + return "vector<Y>"; +} +string VectorOverload(vector<string> v) { + return "vector<string>"; +} +string VectorOverload(vector<int> v) { + return "vector<int>"; +} +%} diff --git a/Examples/test-suite/octave/li_std_containers_overload_runme.m b/Examples/test-suite/octave/li_std_containers_overload_runme.m new file mode 100644 index 000000000..786d63466 --- /dev/null +++ b/Examples/test-suite/octave/li_std_containers_overload_runme.m @@ -0,0 +1,37 @@ +# do not dump Octave core +if exist("crash_dumps_octave_core", "builtin") + crash_dumps_octave_core(0); +endif + +li_std_containers_overload + +function check(got, expected) + if (!strcmp(got, expected)) + error("Failed check. '%s' != '%s'", got, expected) + endif +end + +v = VectorX(); +check(VectorOverload(v), "vector<X>"); + +v = VectorY(); +check(VectorOverload(v), "vector<Y>"); + +v = VectorInt(); +check(VectorOverload(v), "vector<int>"); + +v = VectorString(); +check(VectorOverload(v), "vector<string>"); + +# TODO: Conversion from an Octave sequence not implemented yet +# v = {X()}; +# check(VectorOverload(v), "vector<X>"); + +# v = {Y()}; +# check(VectorOverload(v), "vector<Y>"); + +# v = {1, 2, 3}; +# check(VectorOverload(v), "vector<int>"); + +# v = {"aaa", "bbb", "ccc"}; +# check(VectorOverload(v), "vector<string>"); diff --git a/Examples/test-suite/python/li_std_containers_overload_runme.py b/Examples/test-suite/python/li_std_containers_overload_runme.py new file mode 100644 index 000000000..dcb383511 --- /dev/null +++ b/Examples/test-suite/python/li_std_containers_overload_runme.py @@ -0,0 +1,29 @@ +from li_std_containers_overload import * + +def check(got, expected): + if got != expected: + raise RuntimeError("Failed check. '{}' != '{}'".format(got, expected)) + +v = VectorX() +check(VectorOverload(v), "vector<X>") + +v = VectorY() +check(VectorOverload(v), "vector<Y>") + +v = VectorInt() +check(VectorOverload(v), "vector<int>") + +v = VectorString() +check(VectorOverload(v), "vector<string>") + +v = [X()] +check(VectorOverload(v), "vector<X>") + +v = [Y()] +check(VectorOverload(v), "vector<Y>") + +v = [1, 2, 3] +check(VectorOverload(v), "vector<int>") + +v = ["aaa", "bbb", "ccc"] +check(VectorOverload(v), "vector<string>") diff --git a/Examples/test-suite/ruby/li_std_containers_overload_runme.rb b/Examples/test-suite/ruby/li_std_containers_overload_runme.rb new file mode 100644 index 000000000..913b6113a --- /dev/null +++ b/Examples/test-suite/ruby/li_std_containers_overload_runme.rb @@ -0,0 +1,44 @@ +#!/usr/bin/env ruby +# +# Put description here +# +# +# +# +# + +require 'swig_assert' + +require 'li_std_containers_overload' + +include Li_std_containers_overload + +def check(got, expected) + if (got != expected) + raise RuntimeError, "Failed check. '#{got}' != '#{expected}'" + end +end + +v = VectorX.new() +check(VectorOverload(v), "vector<X>") + +v = VectorY.new() +check(VectorOverload(v), "vector<Y>") + +v = VectorInt.new() +check(VectorOverload(v), "vector<int>") + +v = VectorString.new() +check(VectorOverload(v), "vector<string>") + +v = [X.new()] +check(VectorOverload(v), "vector<X>") + +v = [Y.new()] +check(VectorOverload(v), "vector<Y>") + +v = [1, 2, 3] +check(VectorOverload(v), "vector<int>") + +v = ["aaa", "bbb", "ccc"] +check(VectorOverload(v), "vector<string>") diff --git a/Lib/octave/octcontainer.swg b/Lib/octave/octcontainer.swg index 269ff7544..310a849d9 100644 --- a/Lib/octave/octcontainer.swg +++ b/Lib/octave/octcontainer.swg @@ -401,20 +401,14 @@ namespace swig return const_reference(_seq, n); } - bool check(bool set_err = true) const + bool check() const { int s = size(); for (int i = 0; i < s; ++i) { // swig::SwigVar_PyObject item = OctSequence_GetItem(_seq, i); octave_value item; // * todo - if (!swig::check<value_type>(item)) { - if (set_err) { - char msg[1024]; - sprintf(msg, "in sequence element %d", i); - SWIG_Error(SWIG_RuntimeError, msg); - } + if (!swig::check<value_type>(item)) return false; - } } return true; } diff --git a/Lib/python/pycontainer.swg b/Lib/python/pycontainer.swg index ef2f725af..fef4e9b3b 100644 --- a/Lib/python/pycontainer.swg +++ b/Lib/python/pycontainer.swg @@ -672,19 +672,13 @@ namespace swig return const_reference(_seq, n); } - bool check(bool set_err = true) const + bool check() const { Py_ssize_t s = size(); for (Py_ssize_t i = 0; i < s; ++i) { swig::SwigVar_PyObject item = PySequence_GetItem(_seq, i); - if (!swig::check<value_type>(item)) { - if (set_err) { - char msg[1024]; - sprintf(msg, "in sequence element %d", (int)i); - SWIG_Error(SWIG_RuntimeError, msg); - } + if (!swig::check<value_type>(item)) return false; - } } return true; } diff --git a/Lib/ruby/rubycontainer.swg b/Lib/ruby/rubycontainer.swg index e8830a715..9fa205bf5 100644 --- a/Lib/ruby/rubycontainer.swg +++ b/Lib/ruby/rubycontainer.swg @@ -395,19 +395,13 @@ namespace swig return const_reference(_seq, n); } - bool check(bool set_err = false) const + bool check() const { int s = (int) size(); for (int i = 0; i < s; ++i) { VALUE item = rb_ary_entry(_seq, i ); - if (!swig::check<value_type>(item)) { - if (set_err) { - char msg[1024]; - sprintf(msg, "in sequence element %d", i); - SWIG_Error(SWIG_RuntimeError, msg); - } + if (!swig::check<value_type>(item)) return false; - } } return true; } |