Repository: cython/cython

Issue:
[BUG] cython.final extension type with fused type method
### Describe the bug

When using `cython.final` decorator for a `cdef class` that has a method with an argument of  fused type, the generated C code lacks some prefix `__pyx_fuse_0` and `__pyx_fuse_1` in a few places.
The code compiles without error. But when loading/importing one gets an error:
```
ImportError: dlopen(XXX.cpython-311-darwin.so, 0x0002): symbol not found in flat namespace '___pyx_f_54_cython_magic_570ee92356009cb8197cfd5d5ebfbcc01ad73c1d_6AClass_c_sum'
```

### Code to reproduce the behaviour:

```cython
import cython
%load_ext cython

# %%
%%cython

import cython
import numpy as np

ctypedef unsigned char uint8_t
ctypedef unsigned short uint16_t
ctypedef fused uint_fused:
    uint8_t
    uint16_t

@cython.final
cdef class AClass:
    def compute_sum(self, a):
        if a.dtype == np.float32:
            return self.c_sum[uint8_t](a)
        else:
            return self.c_sum[uint16_t](a)

    cdef c_sum(self, uint_fused[:] a):
        cdef:
            int i
            uint16_t s = 0
        for i in range(a.shape[0]):
            s += a[i]
        return s

# %%
aclass = AClass()
aclass.compute_sum(np.arange(10).astype(np.uint16))
```
Note that without the `@cython.final`, everything works as expected without error.

### Expected behaviour

No error, result 45.

### OS

macOS

### Python version

3.11.7

### Cython version

3.0.8

### Additional context

_No response_


Discussion:
@da-woods You seem active right now and this is a road blocker for one of my projects.
I'll try to have a look in the next week or so. I should warn: this fused stuff is usually quite heavy going to debug and fix, so I'm really not going to promise anything quick.
Thanks for having a look.
A striking argument for Cython is allocating numpy arrays in Python and then use memoryviews in Cython, in particular in a prange. Then one quickly wants c++ templates, the next best thing being fused types, last resort tempita.

So the combination of C++ with memoryviews would be super helpful, but the C(++) structure of memoryviews is quite hidden.

TLDR: If Cython works, it‘s very cool. If it doesn’t, try n error can drive you crazy 😜 

Resolving patch:
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -3555,6 +3555,8 @@ def specialize_entry(entry, cname):
 
     if entry.func_cname:
         entry.func_cname = get_fused_cname(cname, entry.func_cname)
+    if entry.final_func_cname:
+        entry.final_func_cname = get_fused_cname(cname, entry.final_func_cname)
 
 def get_fused_cname(fused_cname, orig_cname):
     """


Test patch:
diff --git a/tests/run/fused_cdef.pyx b/tests/run/fused_cdef.pyx
new file mode 100644
--- /dev/null
+++ b/tests/run/fused_cdef.pyx
@@ -0,0 +1,21 @@
+# mode: run
+
+cimport cython
+
+@cython.final
+cdef class AClass:
+    cdef c_do_something(self, cython.integral x):
+        return cython.typeof(x), x
+
+    def do_something(self, x, selector):
+        """
+        >>> i = AClass()
+        >>> i.do_something(1, True)
+        ('short', 1)
+        >>> i.do_something(2, False)
+        ('long', 2)
+        """
+        if selector:
+            return self.c_do_something[short](x)
+        else:
+            return self.c_do_something[long](x)