summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2023-01-04 10:02:35 +0000
committerGitHub <noreply@github.com>2023-01-04 11:02:35 +0100
commit08e44780f027ce2d8306557d73a5c07b4dea66a6 (patch)
tree7be46eed375c698afaf199f22edc375063c0035f
parent60fe73184a855b5a0bcd3a1cf6c2b3993e2bafee (diff)
downloadcython-08e44780f027ce2d8306557d73a5c07b4dea66a6.tar.gz
Add support of const fused type memory views (GH-3118) (GH-5076)
Backport of https://github.com/cython/cython/pull/3118 Fixes https://github.com/cython/cython/issues/3783 Co-authored-by: Thomas VINCENT <thomas.vincent@esrf.fr>
-rw-r--r--Cython/Compiler/PyrexTypes.py1
-rw-r--r--tests/errors/fused_types.pyx34
-rw-r--r--tests/memoryview/numpy_memoryview_readonly.pyx50
-rw-r--r--tests/run/fused_types.pyx53
4 files changed, 126 insertions, 12 deletions
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index 922c39367..c309bd04b 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -1561,6 +1561,7 @@ class PythranExpr(CType):
class CConstType(BaseType):
is_const = 1
+ subtypes = ['const_base_type']
def __init__(self, const_base_type):
self.const_base_type = const_base_type
diff --git a/tests/errors/fused_types.pyx b/tests/errors/fused_types.pyx
index 438e46584..6d9dd6879 100644
--- a/tests/errors/fused_types.pyx
+++ b/tests/errors/fused_types.pyx
@@ -1,4 +1,5 @@
# mode: error
+# ticket: 1772
cimport cython
from cython import fused_type
@@ -64,17 +65,30 @@ ctypedef fused fused2:
func(x, y)
+cdef fused mix_const_t:
+ int
+ const int
+
+cdef cdef_func_with_mix_const_type(mix_const_t val):
+ print(val)
+
+# Mixing const and non-const type makes fused type ambiguous
+cdef_func_with_mix_const_type(1)
+
+
_ERRORS = u"""
-10:15: fused_type does not take keyword arguments
-15:33: Type specified multiple times
-26:0: Invalid use of fused types, type cannot be specialized
-26:4: Not enough types specified to specialize the function, int2_t is still fused
+11:15: fused_type does not take keyword arguments
+16:33: Type specified multiple times
27:0: Invalid use of fused types, type cannot be specialized
27:4: Not enough types specified to specialize the function, int2_t is still fused
-28:16: Call with wrong number of arguments (expected 2, got 1)
-29:16: Call with wrong number of arguments (expected 2, got 3)
-36:6: Invalid base type for memoryview slice: int *
-39:0: Fused lambdas not allowed
-42:5: Fused types not allowed here
-45:9: Fused types not allowed here
+28:0: Invalid use of fused types, type cannot be specialized
+28:4: Not enough types specified to specialize the function, int2_t is still fused
+29:16: Call with wrong number of arguments (expected 2, got 1)
+30:16: Call with wrong number of arguments (expected 2, got 3)
+37:6: Invalid base type for memoryview slice: int *
+40:0: Fused lambdas not allowed
+43:5: Fused types not allowed here
+46:9: Fused types not allowed here
+76:0: Invalid use of fused types, type cannot be specialized
+76:29: ambiguous overloaded method
"""
diff --git a/tests/memoryview/numpy_memoryview_readonly.pyx b/tests/memoryview/numpy_memoryview_readonly.pyx
index 20b6c7393..f1b289968 100644
--- a/tests/memoryview/numpy_memoryview_readonly.pyx
+++ b/tests/memoryview/numpy_memoryview_readonly.pyx
@@ -1,10 +1,14 @@
# mode: run
# tag: readonly, const, numpy
+# ticket: 1772
import numpy as np
+cimport cython
-def new_array():
- return np.arange(10).astype('float')
+def new_array(dtype='float', writeable=True):
+ array = np.arange(10, dtype=dtype)
+ array.setflags(write=writeable)
+ return array
ARRAY = new_array()
@@ -124,3 +128,45 @@ def test_copy():
rw[1] = 2
rw2[2] = 2
return rw[0], rw[1], rw[2], rw2[0], rw2[1], rw2[2]
+
+
+cdef getmax_floating(const cython.floating[:] x):
+ """Function with fused type, should work with both ro and rw memoryviews"""
+ cdef cython.floating max_val = - float('inf')
+ for val in x:
+ if val > max_val:
+ max_val = val
+ return max_val
+
+
+def test_mmview_const_fused_cdef():
+ """Test cdef function with const fused type memory view as argument.
+
+ >>> test_mmview_const_fused_cdef()
+ """
+ cdef float[:] data_rw = new_array(dtype='float32')
+ assert getmax_floating(data_rw) == 9
+
+ cdef const float[:] data_ro = new_array(dtype='float32', writeable=False)
+ assert getmax_floating(data_ro) == 9
+
+
+def test_mmview_const_fused_def(const cython.floating[:] x):
+ """Test def function with const fused type memory view as argument.
+
+ With read-write numpy array:
+
+ >>> test_mmview_const_fused_def(new_array('float32', writeable=True))
+ 0.0
+ >>> test_mmview_const_fused_def(new_array('float64', writeable=True))
+ 0.0
+
+ With read-only numpy array:
+
+ >>> test_mmview_const_fused_def(new_array('float32', writeable=False))
+ 0.0
+ >>> test_mmview_const_fused_def(new_array('float64', writeable=False))
+ 0.0
+ """
+ cdef cython.floating result = x[0]
+ return result
diff --git a/tests/run/fused_types.pyx b/tests/run/fused_types.pyx
index 7b27b9449..de63fbdd0 100644
--- a/tests/run/fused_types.pyx
+++ b/tests/run/fused_types.pyx
@@ -1,4 +1,5 @@
# mode: run
+# ticket: 1772
cimport cython
from cython.view cimport array
@@ -363,6 +364,22 @@ def test_fused_memslice_dtype_repeated_2(cython.floating[:] array1, cython.float
"""
print cython.typeof(array1), cython.typeof(array2), cython.typeof(array3)
+def test_fused_const_memslice_dtype_repeated(const cython.floating[:] array1, cython.floating[:] array2):
+ """Test fused types memory view with one being const
+
+ >>> sorted(test_fused_const_memslice_dtype_repeated.__signatures__)
+ ['double', 'float']
+
+ >>> test_fused_const_memslice_dtype_repeated(get_array(8, 'd'), get_array(8, 'd'))
+ const double[:] double[:]
+ >>> test_fused_const_memslice_dtype_repeated(get_array(4, 'f'), get_array(4, 'f'))
+ const float[:] float[:]
+ >>> test_fused_const_memslice_dtype_repeated(get_array(8, 'd'), get_array(4, 'f'))
+ Traceback (most recent call last):
+ ValueError: Buffer dtype mismatch, expected 'double' but got 'float'
+ """
+ print cython.typeof(array1), cython.typeof(array2)
+
def test_cython_numeric(cython.numeric arg):
"""
Test to see whether complex numbers have their utility code declared
@@ -388,6 +405,18 @@ def test_index_fused_args(cython.floating f, ints_t i):
"""
_test_index_fused_args[cython.floating, ints_t](f, i)
+cdef _test_index_const_fused_args(const cython.floating f, const ints_t i):
+ print(cython.typeof(f), cython.typeof(i))
+
+def test_index_const_fused_args(const cython.floating f, const ints_t i):
+ """Test indexing function implementation with const fused type args
+
+ >>> import cython
+ >>> test_index_const_fused_args[cython.double, cython.int](2.0, 3)
+ ('const double', 'const int')
+ """
+ _test_index_const_fused_args[cython.floating, ints_t](f, i)
+
def test_composite(fused_composite x):
"""
@@ -404,6 +433,30 @@ def test_composite(fused_composite x):
return 2 * x
+cdef cdef_func_const_fused_arg(const cython.floating val,
+ const fused_type1 * ptr_to_const,
+ const (cython.floating *) const_ptr):
+ print(val, cython.typeof(val))
+ print(ptr_to_const[0], cython.typeof(ptr_to_const[0]))
+ print(const_ptr[0], cython.typeof(const_ptr[0]))
+
+ ptr_to_const = NULL # pointer is not const, value is const
+ const_ptr[0] = 0.0 # pointer is const, value is not const
+
+def test_cdef_func_with_const_fused_arg():
+ """Test cdef function with const fused type argument
+
+ >>> test_cdef_func_with_const_fused_arg()
+ (0.0, 'const float')
+ (1, 'const int')
+ (2.0, 'float')
+ """
+ cdef float arg0 = 0.0
+ cdef int arg1 = 1
+ cdef float arg2 = 2.0
+ cdef_func_const_fused_arg(arg0, &arg1, &arg2)
+
+
### see GH3642 - presence of cdef inside "unrelated" caused a type to be incorrectly inferred
cdef unrelated(cython.floating x):
cdef cython.floating t = 1