Commit 3a3419fb authored by Stefan Behnel's avatar Stefan Behnel Committed by GitHub

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)
parents 8abcb26f 6e904633
......@@ -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
......
......@@ -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]
......@@ -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))
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