Repository: cython/cython

Issue:
typeid failed on fused types
```cython
# cython: language=c++
# cython: language_level=3str
from libcpp.typeinfo cimport type_info
from cython.operator cimport typeid
cdef fused C: 
   int 
   object 
cdef const type_info* i32 = &typeid(int) 
cdef f(C x): 
    cdef const type_info* a = &typeid(C) 
    return a  == i32 
     
def g(x): 
   return (x, f(x)) 
```


Discussion:

Resolving patch:
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -655,6 +655,19 @@ def analyse_as_type(self, env):
         # 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.
@@ -10826,7 +10839,7 @@ def analyse_types(self, env):
             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


Test patch:
diff --git a/tests/run/fused_cpp.pyx b/tests/run/fused_cpp.pyx
--- 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
--- 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))