summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2020-04-18 22:39:33 +0200
committerGitHub <noreply@github.com>2020-04-18 22:39:33 +0200
commit3a3419fb1f13a0ec8ba1121f0aea4e7ec4df4773 (patch)
tree863123e42aebd06fdc27ca840c33aa22803f4547
parent8abcb26f075a7985a71a37f9320252019ef4bfe7 (diff)
parent6e904633f13faa7dc36015a900bd8ab06abc6b8f (diff)
downloadcython-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.py15
-rw-r--r--tests/run/fused_cpp.pyx27
-rw-r--r--tests/run/fused_types.pyx31
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))