diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2020-04-18 22:39:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-18 22:39:33 +0200 |
commit | 3a3419fb1f13a0ec8ba1121f0aea4e7ec4df4773 (patch) | |
tree | 863123e42aebd06fdc27ca840c33aa22803f4547 | |
parent | 8abcb26f075a7985a71a37f9320252019ef4bfe7 (diff) | |
parent | 6e904633f13faa7dc36015a900bd8ab06abc6b8f (diff) | |
download | cython-3a3419fb1f13a0ec8ba1121f0aea4e7ec4df4773.tar.gz |
Make C++ typeid accept specializations of fused types (#3205)
* Potential fix for GH issue #3203
Gets the specialized type if possible from
NameNode.analyse_as_type
This does introduce a potential new bug:
```
cimport cython
just_float = cython.fused_type(float)
cdef OK1(just_float x):
return just_float in floating
cdef fail1(just_float x, floating y):
return just_float in floating
cdef fail2(floating x):
return floating in floating
def show():
"""
>>> show()
True
True
True
True
"""
print(OK1(1.0))
print(fail1(1.0, 2.0))
print(fail1[float, double](1.0, 2.0))
print(fail2[float](1.0))
```
fail1 and fail2 work before this patch but fail with it. It isn't
clear to me if this should actually be considered a bug. It
works in both versions with `cython.floating`, which possibly
suggests analyse_as_type in AttributeNode should also be changed
* Bring attribute.fused types in line
* Removed try-catch
* Fix and test "type in fused_type" special-case
* Added "analyse_as_specialized_type"
* Fixed cpp_operators (handle type is None)
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 15 | ||||
-rw-r--r-- | tests/run/fused_cpp.pyx | 27 | ||||
-rw-r--r-- | tests/run/fused_types.pyx | 31 |
3 files changed, 72 insertions, 1 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 54eac127f..dcd327923 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -655,6 +655,19 @@ class ExprNode(Node): # type, return that type, else None. return None + def analyse_as_specialized_type(self, env): + type = self.analyse_as_type(env) + if type and type.is_fused and env.fused_to_specific: + # while it would be nice to test "if entry.type in env.fused_to_specific" + # rather than try/catch this doesn't work reliably (mainly for nested fused types) + try: + return type.specialize(env.fused_to_specific) + except KeyError: + pass + if type and type.is_fused: + error(self.pos, "Type is not specific") + return type + def analyse_as_extension_type(self, env): # If this node can be interpreted as a reference to an # extension type or builtin type, return its type, else None. @@ -10862,7 +10875,7 @@ class TypeidNode(ExprNode): self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator") return self self.type = type_info - as_type = self.operand.analyse_as_type(env) + as_type = self.operand.analyse_as_specialized_type(env) if as_type: self.arg_type = as_type self.is_type = True diff --git a/tests/run/fused_cpp.pyx b/tests/run/fused_cpp.pyx index c5a0d7d34..9f3bb5104 100644 --- a/tests/run/fused_cpp.pyx +++ b/tests/run/fused_cpp.pyx @@ -2,6 +2,8 @@ cimport cython from libcpp.vector cimport vector +from libcpp.typeinfo cimport type_info +from cython.operator cimport typeid def test_cpp_specialization(cython.floating element): """ @@ -14,3 +16,28 @@ def test_cpp_specialization(cython.floating element): cdef vector[cython.floating] *v = new vector[cython.floating]() v.push_back(element) print cython.typeof(v), cython.typeof(element), v.at(0) + +cdef fused C: + int + object + +cdef const type_info* tidint = &typeid(int) +def typeid_call(C x): + """ + For GH issue 3203 + >>> typeid_call(1) + True + """ + cdef const type_info* a = &typeid(C) + return a[0] == tidint[0] + +cimport cython + +def typeid_call2(cython.integral x): + """ + For GH issue 3203 + >>> typeid_call2[int](1) + True + """ + cdef const type_info* a = &typeid(cython.integral) + return a[0] == tidint[0] diff --git a/tests/run/fused_types.pyx b/tests/run/fused_types.pyx index 5d30cd440..649c4f074 100644 --- a/tests/run/fused_types.pyx +++ b/tests/run/fused_types.pyx @@ -21,6 +21,7 @@ ctypedef double *p_double ctypedef int *p_int fused_type3 = cython.fused_type(int, double) fused_composite = cython.fused_type(fused_type2, fused_type3) +just_float = cython.fused_type(float) def test_pure(): """ @@ -453,3 +454,33 @@ def test_cdef_func_with_const_fused_arg(): cdef int arg1 = 1 cdef float arg2 = 2.0 cdef_func_const_fused_arg(arg0, &arg1, &arg2) + + +cdef in_check_1(just_float x): + return just_float in floating + +cdef in_check_2(just_float x, floating y): + # the "floating" on the right-hand side of the in statement should not be specialized + # - the test should still work. + return just_float in floating + +cdef in_check_3(floating x): + # the floating on the left-hand side of the in statement should be specialized + # but the one of the right-hand side should not (so that the test can still work). + return floating in floating + +def test_fused_in_check(): + """ + It should be possible to use fused types on in "x in ...fused_type" statements + even if that type is specialized in the function. + + >>> test_fused_in_check() + True + True + True + True + """ + print(in_check_1(1.0)) + print(in_check_2(1.0, 2.0)) + print(in_check_2[float, double](1.0, 2.0)) + print(in_check_3[float](1.0)) |