Repository: cython/cython
Pull request: Fix a bug where fused_to_specific was applied too widely
Fixes https://github.com/cython/cython/issues/3642

Problem statement:
fused type variable declared in unrelated function causes incorrect type inference
The following example
```cython
cimport cython

cdef unrelated(cython.floating x):
    cdef cython.floating t

cdef handle_float(float* x): pass
cdef handle_double(double* x): pass

def main(cython.floating x):
    if cython.floating is float:
        handle_float(&x)
    elif cython.floating is double:
        handle_double(&x)
```
currently causes cython (both 0.29.19 and 3.0a5) to incorrectly (AFAICT) error out with
```
Error compiling Cython file:
------------------------------------------------------------
...

def main(cython.floating x):
    if cython.floating is float:
        handle_float(&x)
    elif cython.floating is double:
        handle_double(&x)
                     ^
------------------------------------------------------------

test.pyx:13:22: Cannot assign type 'float *' to 'double *'
```
Note that commenting out the `cdef cython.floating t` declaration removes the error, even though `unrelated` is never used by `main`.

Hints from issue discussion:
I think (but could yet be wrong) that it's https://github.com/cython/cython/blob/0532a0919be640210eeba1144717a6273707e112/Cython/Compiler/Nodes.py#L1035

cythonscope is having the attribute `fused_to_specific` set on it, and that influences all subsequent lookups. Not sure right now how it should be fixed though.

Commit message: Fix a bug where fused_to_specific was applied too widely

Fixes https://github.com/cython/cython/issues/3642

Patch to review:
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index c9a0422814a..1ef0ab9c57a 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -1031,8 +1031,6 @@ def analyse(self, env, could_be_name=False):
                 if scope is None:
                     # Maybe it's a cimport.
                     scope = env.find_imported_module(self.module_path, self.pos)
-                    if scope:
-                        scope.fused_to_specific = env.fused_to_specific
             else:
                 scope = env
 
diff --git a/tests/run/fused_types.pyx b/tests/run/fused_types.pyx
index 649c4f0742d..01a9e18d383 100644
--- a/tests/run/fused_types.pyx
+++ b/tests/run/fused_types.pyx
@@ -484,3 +484,25 @@ def test_fused_in_check():
     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))
+
+### see GH3642 - presence of cdef inside "unrelated" caused a type to be incorrectly inferred
+cdef unrelated(cython.floating x):
+    cdef cython.floating t
+
+cdef handle_float(float* x): return 'float'
+
+cdef handle_double(double* x): return 'double'
+
+def convert_to_ptr(cython.floating x):
+    """
+    >>> convert_to_ptr(1.0)
+    'double'
+    >>> convert_to_ptr['double'](1.0)
+    'double'
+    >>> convert_to_ptr['float'](1.0)
+    'float'
+    """
+    if cython.floating is float:
+        return handle_float(&x)
+    elif cython.floating is double:
+        return handle_double(&x)


Code review comments:
diff_hunk: @@ -484,3 +484,25 @@ def test_fused_in_check():
     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))
+
+### see GH3642 - presence of cdef inside "unrelated" caused a type to be incorrectly inferred
+cdef unrelated(cython.floating x):
+    cdef cython.floating t
path: tests/run/fused_types.pyx
text: @user1:
Would be nice if we could avoid a C compiler warning about unused code here.