From e7971ccbcd7a38f0a72f24382fffaaaf55dc781c Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Wed, 20 May 2026 16:12:34 +0100 Subject: [PATCH 1/3] Avoid nested ArrayTypes on StructureType types --- .../psyir/nodes/structure_reference.py | 2 ++ .../psyir/nodes/structure_reference_test.py | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/psyclone/psyir/nodes/structure_reference.py b/src/psyclone/psyir/nodes/structure_reference.py index 97cf6ded32..f458f1d484 100644 --- a/src/psyclone/psyir/nodes/structure_reference.py +++ b/src/psyclone/psyir/nodes/structure_reference.py @@ -364,6 +364,8 @@ def _get_cursor_shape(cursor, cursor_type): shape = cursor_shape if shape: + if isinstance(cursor_type, ArrayType): + return ArrayType(cursor_type.elemental_type, shape) return ArrayType(cursor_type, shape) # We must have a scalar. diff --git a/src/psyclone/tests/psyir/nodes/structure_reference_test.py b/src/psyclone/tests/psyir/nodes/structure_reference_test.py index dc333261fc..23a324a5d1 100644 --- a/src/psyclone/tests/psyir/nodes/structure_reference_test.py +++ b/src/psyclone/tests/psyir/nodes/structure_reference_test.py @@ -43,6 +43,7 @@ from psyclone.core import Signature from psyclone.errors import GenerationError, InternalError from psyclone.psyir import symbols, nodes +from psyclone.psyir.symbols.datatypes import ArrayType, ScalarType from psyclone.tests.utilities import check_links @@ -240,7 +241,7 @@ def test_struct_ref_semantic_nav(): "found: ['broken']" in str(err.value)) -def test_struct_ref_datatype(): +def test_struct_ref_datatype(fortran_reader): '''Test the datatype() method of StructureReference.''' atype = symbols.ArrayType(symbols.REAL_TYPE, [10, 8]) rtype = symbols.StructureType.create([ @@ -327,6 +328,25 @@ def test_struct_ref_datatype(): create(ssym, ["nx"], overwrite_datatype=symbols.REAL_TYPE) assert sref.datatype == symbols.REAL_TYPE + # Test that the structuretype datatype for this case does not contain + # multiply nested array types. + code = ( + "subroutine test(n,m)\n" + " integer :: n, m\n" + " type :: array_type\n" + " real :: array(10,10)\n" + " end type\n" + " type(array_type) :: ref\n" + " real :: result\n" + " integer :: dimension\n" + " result = maxval(ref%array)\n" + "end subroutine\n") + psyir = fortran_reader.psyir_from_source(code) + node = psyir.walk(nodes.StructureReference)[0] + assert isinstance(node.datatype, ArrayType) + assert isinstance(node.datatype.elemental_type, ScalarType) + assert node.datatype.elemental_type.intrinsic == ScalarType.Intrinsic.REAL + def test_structure_reference_unresolved_type(): ''' From d8172cd9ca456057637a8e44334b5ff1b050659b Mon Sep 17 00:00:00 2001 From: LonelyCat124 <3043914+LonelyCat124@users.noreply.github.com.> Date: Thu, 21 May 2026 13:52:11 +0100 Subject: [PATCH 2/3] Remove leftover TODOs --- src/psyclone/psyir/nodes/intrinsic_call.py | 73 +++--------------- .../tests/psyir/nodes/intrinsic_call_test.py | 75 ------------------- 2 files changed, 12 insertions(+), 136 deletions(-) diff --git a/src/psyclone/psyir/nodes/intrinsic_call.py b/src/psyclone/psyir/nodes/intrinsic_call.py index 1a84fd5c37..7f4c7f93fd 100644 --- a/src/psyclone/psyir/nodes/intrinsic_call.py +++ b/src/psyclone/psyir/nodes/intrinsic_call.py @@ -427,36 +427,6 @@ def _int_return_type(node: IntrinsicCall) -> DataType: ) -def _iparity_return_type(node: IntrinsicCall) -> DataType: - """Helper function for the IPARITY case. - - The result is the same type as the "array" argument. If the - "dim" argument is not present, a scalar of that type is returned. - Otherwise an ArrayType of rank n-1 (where n is the rank of "array") of - that type is returned instead. - - :param node: The IntrinsicCall whose return type to compute. - - :returns: the computed datatype for the IntrinsicCall. - """ - # TODO #3415: Replace with _type_of_named_arg_accounting_for_dim_arg( - # node, "array"). - dtype = ScalarType( - node.argument_by_name("array").datatype.intrinsic, - node.argument_by_name("array").datatype.precision, - ) - # If dim is not present then we return a scalar. - if "dim" not in node.argument_names: - return dtype - # We have a dimension specified. We don't know the resultant shape - # in any detail as its dependent on the value of dim - return ArrayType( - dtype, - [ArrayType.Extent.DEFERRED] - * (len(node.argument_by_name("array").datatype.shape) - 1), - ) - - def _get_bound_function_return_type(node: IntrinsicCall) -> DataType: """Helper function for the return types of functions like LBOUND and LCOBOUND etc. @@ -554,33 +524,6 @@ def _matmul_return_type(node: IntrinsicCall) -> DataType: return ArrayType(stype, shape) -def _maxval_return_type(node: IntrinsicCall) -> DataType: - """ Helper function for the MAXVAL (and similar) intrinsic return - types. - - If the "dim" argument is absent, or the "array" argument has rank one - then the result is a ScalarType of the type of the "array" argument. - Otherwise the result is an ArrayType of rank n-1 (where n is the rank of - the "array" argument) with the same datatype of the "array" argument. - - :param node: The IntrinsicCall whose return type to compute. - - :returns: the computed datatype for the IntrinsicCall. - """ - # TODO #3415: Replace with _type_of_named_arg_accounting_for_dim_arg( - # node, "array"). - dtype = ScalarType( - node.argument_by_name("array").datatype.intrinsic, - node.argument_by_name("array").datatype.precision - ) - arg = node.argument_by_name("array") - if "dim" not in node.argument_names: - return dtype - # We have a dimension specified. We don't know the resultant shape - # in any detail as its dependent on the value of dim - return _type_of_arg_with_rank_minus_one(arg, dtype) - - def _dot_product_return_type(node: IntrinsicCall) -> DataType: """Helper value for DOT_PRODUCT intrinsic return type. @@ -2858,7 +2801,9 @@ class Intrinsic(IAttr, Enum): ) ), optional_args={"mask": DataNode}, - return_type=_iparity_return_type, + return_type=lambda node: ( + _type_of_named_arg_accounting_for_dim_arg(node, "array") + ), reference_accesses=lambda node: ( _compute_reference_accesses( node @@ -3381,7 +3326,9 @@ class Intrinsic(IAttr, Enum): ) ), optional_args={"mask": DataNode}, - return_type=_maxval_return_type, + return_type=lambda node: ( + _type_of_named_arg_accounting_for_dim_arg(node, "array") + ), reference_accesses=lambda node: ( _compute_reference_accesses( node @@ -3510,7 +3457,9 @@ class Intrinsic(IAttr, Enum): ) ), optional_args={"mask": DataNode}, - return_type=_maxval_return_type, + return_type=lambda node: ( + _type_of_named_arg_accounting_for_dim_arg(node, "array") + ), reference_accesses=lambda node: ( _compute_reference_accesses( node, @@ -4063,7 +4012,9 @@ class Intrinsic(IAttr, Enum): optional_args={"mask": DataNode, "identity": DataNode, "ordered": DataNode}, - return_type=_maxval_return_type, + return_type=lambda node: ( + _type_of_named_arg_accounting_for_dim_arg(node, "array") + ), reference_accesses=lambda node: ( _compute_reference_accesses( node diff --git a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py index ae1a7053ce..f2837fed3a 100644 --- a/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py +++ b/src/psyclone/tests/psyir/nodes/intrinsic_call_test.py @@ -70,10 +70,8 @@ _type_of_intrinsic_with_precision_of_named_arg, _findloc_return_type, _int_return_type, - _iparity_return_type, _get_bound_function_return_type, _matmul_return_type, - _maxval_return_type, ) from psyclone.psyir.symbols import ( ArrayType, @@ -1390,39 +1388,6 @@ def test_int_return_type(fortran_reader): assert rtype.precision.symbol.name == "wp" -def test_iparity_return_type(fortran_reader): - """Test the _iparity_return_type helper function.""" - code = """ - subroutine x - integer, dimension(100, 100) :: array - integer :: k - k = IPARITY(array) - end subroutine x - """ - # TODO #3415: Test is superfluous with this issue fixed. - psyir = fortran_reader.psyir_from_source(code) - # TODO #3268 Can't iparity directily with fortran reader, so need to - # create the Intrinsics manually using the psyir from the generated code. - intrinsic = psyir.walk(Call)[0] - intrinsic = IntrinsicCall.create( - IntrinsicCall.Intrinsic.IPARITY, - [x.copy() for x in intrinsic.arguments] - ) - - assert _iparity_return_type(intrinsic) == INTEGER_TYPE - - k_sym = psyir.children[0].symbol_table.lookup("k") - intrinsic = psyir.walk(Call)[0] - intrinsic = IntrinsicCall.create( - IntrinsicCall.Intrinsic.IPARITY, - [("array", intrinsic.arguments[0].copy()), ("dim", Reference(k_sym))], - ) - res = _iparity_return_type(intrinsic) - assert isinstance(res, ArrayType) - assert len(res.shape) == 1 - assert res.shape[0] == ArrayType.Extent.DEFERRED - - def test_get_bound_function_return_type(fortran_reader): """Test the _get_bound_function_return_type helper function.""" code = """subroutine x @@ -1557,46 +1522,6 @@ def test_matmul_return_type(fortran_reader): assert res.shape[1].upper.arguments[1].value == "2" -def test_maxval_return_type(fortran_reader): - '''Test for the _maxval_return_type function.''' - # TODO #3415: Test is superfluous with this issue fixed. - code = """subroutine test - integer, parameter :: wp = 8 - integer*8, dimension(100,100) :: x - integer, dimension(100) :: z - integer(kind=wp), dimension(100) :: m - integer :: y - y = MAXVAL(x) - z = MAXVAL(x, dim=2) - y = MAXVAL(m) - end subroutine test - """ - psyir = fortran_reader.psyir_from_source(code) - intrs = psyir.walk(IntrinsicCall) - - # Input is a int*8 so the return type should be an int*8 - res = _maxval_return_type(intrs[0]) - assert res.intrinsic == ScalarType.Intrinsic.INTEGER - assert res.precision == 8 - - # Input is a 2D array of int*8 with dim specified so the result - # is a 1D int*8 array. - res = _maxval_return_type(intrs[1]) - assert isinstance(res, ArrayType) - assert res.intrinsic == ScalarType.Intrinsic.INTEGER - assert res.precision == 8 - assert len(res.shape) == 1 - assert res.shape[0] == ArrayType.Extent.DEFERRED - - # Input is a 1D array of int(kind=wp) so the result is an - # int(kind=wp) - res = _maxval_return_type(intrs[2]) - assert isinstance(res, ScalarType) - assert res.intrinsic == ScalarType.Intrinsic.INTEGER - assert isinstance(res.precision, Reference) - assert res.precision.symbol.name == "wp" - - @pytest.mark.parametrize( "code, expected", [ From fd7fbd4e9e2fb56699bbce9ad9e4950385781882 Mon Sep 17 00:00:00 2001 From: Sergi Siso Date: Thu, 21 May 2026 14:05:18 +0100 Subject: [PATCH 3/3] #3415 Update changelog --- changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog b/changelog index 31d3976fd0..7edcb15b71 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,6 @@ + 22) PR #3439 for #3415. Fix datatype method for StructureReference nodes + that return arrays. + 21) PR #3434 for #2813. Migrates the setup files to use a pyproject.toml rather than setup.py.