diff --git a/doc/user_guide/transformations.rst b/doc/user_guide/transformations.rst index 7fd87a0b41..f41f991468 100644 --- a/doc/user_guide/transformations.rst +++ b/doc/user_guide/transformations.rst @@ -344,11 +344,6 @@ can be found in the API-specific sections). :members: apply :no-index: -.. warning:: This transformation assumes that the MAX Intrinsic acts on - PSyIR Real scalar data and does not check that this is - not the case. Once issue #658 is on master then this - limitation can be fixed. - #### .. autoclass:: psyclone.psyir.transformations.Maxval2LoopTrans @@ -361,11 +356,6 @@ can be found in the API-specific sections). :members: apply :no-index: -.. warning:: This transformation assumes that the MIN Intrinsic acts on - PSyIR Real scalar data and does not check that this is - not the case. Once issue #658 is on master then this - limitation can be fixed. - #### .. autoclass:: psyclone.psyir.transformations.Minval2LoopTrans diff --git a/src/psyclone/psyir/transformations/intrinsics/minormax2code_trans.py b/src/psyclone/psyir/transformations/intrinsics/minormax2code_trans.py index 73aa14bcd6..42b1110e1c 100644 --- a/src/psyclone/psyir/transformations/intrinsics/minormax2code_trans.py +++ b/src/psyclone/psyir/transformations/intrinsics/minormax2code_trans.py @@ -47,11 +47,13 @@ from abc import ABC import warnings -from psyclone.psyir.nodes import BinaryOperation, Assignment, \ - Reference, IfBlock -from psyclone.psyir.symbols import DataSymbol, REAL_TYPE -from psyclone.psyir.transformations.intrinsics.intrinsic2code_trans import \ - Intrinsic2CodeTrans +from psyclone.psyir.nodes import ( + BinaryOperation, Assignment, Reference, IfBlock, IntrinsicCall +) +from psyclone.psyir.symbols import DataSymbol +from psyclone.psyir.transformations.intrinsics.intrinsic2code_trans import ( + Intrinsic2CodeTrans +) from psyclone.utils import transformation_documentation_wrapper @@ -85,7 +87,18 @@ def __init__(self): super().__init__() self._compare_operator = None - def apply(self, node, options=None, **kwargs): + def validate(self, node: IntrinsicCall, options=None, **kwargs): + ''' + Check that it is safe to apply the transformation to the supplied node. + + :param node: the SIGN call to transform. + :param options: any of options for the transformation. + + ''' + super().validate(node, options=options, **kwargs) + super()._validate_scalar_arg(node) + + def apply(self, node: IntrinsicCall, options=None, **kwargs): '''Apply this utility transformation to the specified node. This node must be a MIN or MAX IntrinsicCall. The intrinsic is converted to equivalent inline code. This is implemented as a PSyIR transform from: @@ -117,7 +130,6 @@ def apply(self, node, options=None, **kwargs): this is not the case. :param node: a MIN or MAX intrinsic. - :type node: :py:class:`psyclone.psyir.nodes.IntrinsicCall` :param options: a dictionary with options for transformations. :type options: Optional[Dict[str, Any]] @@ -132,21 +144,14 @@ def apply(self, node, options=None, **kwargs): symbol_table = node.scope.symbol_table assignment = node.ancestor(Assignment) - # Create a temporary result variable. There is an assumption - # here that the Intrinsic returns a PSyIR real type. This - # might not be what is wanted (e.g. the args might PSyIR - # integers), or there may be errors (arguments are of - # different types) but this can't be checked as we don't have - # appropriate methods to query nodes (see #658). + # Create two temporary variables. + result_type = node.arguments[0].datatype res_var_symbol = symbol_table.new_symbol( f"res_{self._intrinsic.name.lower()}", - symbol_type=DataSymbol, datatype=REAL_TYPE) - # Create a temporary variable. Again there is an - # assumption here about the datatype - please see previous - # comment (associated issue #658). + symbol_type=DataSymbol, datatype=result_type) tmp_var_symbol = symbol_table.new_symbol( f"tmp_{self._intrinsic.name.lower()}", - symbol_type=DataSymbol, datatype=REAL_TYPE) + symbol_type=DataSymbol, datatype=result_type) # Replace intrinsic with a temporary (res_var). node.replace_with(Reference(res_var_symbol)) diff --git a/src/psyclone/tests/psyir/frontend/fortran_test.py b/src/psyclone/tests/psyir/frontend/fortran_test.py index 5d873f5e96..150f5d4767 100644 --- a/src/psyclone/tests/psyir/frontend/fortran_test.py +++ b/src/psyclone/tests/psyir/frontend/fortran_test.py @@ -38,6 +38,8 @@ ''' Performs py.test tests on the Fortran PSyIR front-end ''' import pytest +import sys + from psyclone.configuration import Config from psyclone.psyir.frontend.fortran import FortranReader from psyclone.psyir.frontend.fparser2 import Fparser2Reader @@ -97,6 +99,10 @@ def test_fortran_reader_constructor(): # the return value of this function is tested in the following tests freader.psyir_from_source(ONLY_2008_CODE) + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return # Now repeat the process with treesitter Config.get().frontend = "treesitter" freader = FortranReader() diff --git a/src/psyclone/tests/psyir/frontend/fortran_treesitter_reader/ftr_test.py b/src/psyclone/tests/psyir/frontend/fortran_treesitter_reader/ftr_test.py index 33705d3033..5b9ba6ebe6 100644 --- a/src/psyclone/tests/psyir/frontend/fortran_treesitter_reader/ftr_test.py +++ b/src/psyclone/tests/psyir/frontend/fortran_treesitter_reader/ftr_test.py @@ -38,6 +38,7 @@ import logging import pytest +import sys from tree_sitter import Node as TSNode @@ -74,6 +75,10 @@ def test_generate_parse_tree(tmpdir_factory, caplog): Test that generate_parse_tree returns treesitter trees or appropriate error messages. ''' + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return processor = FortranTreeSitterReader() # Valid code returns a treesitter Node @@ -92,7 +97,7 @@ def test_generate_parse_tree(tmpdir_factory, caplog): """ with pytest.raises(ValueError) as err: _ = processor.generate_parse_tree_from_source(invalid_code) - assert "Syntax Error found at line 2" in str(err.value) + assert "Syntax Error found at line" in str(err.value) # Test providing a source file filename = str(tmpdir_factory.mktemp('ts_test').join("testfile.f90")) @@ -120,6 +125,10 @@ def test_generate_psyir(): Test that generate_psyir transforms treesitter parse trees to PSyIR nodes. ''' + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return processor = FortranTreeSitterReader() valid_code = """ @@ -143,6 +152,10 @@ def test_codeblock_generation_and_messages(): Test that NotImplementedErrors are caught and converted to CodeBlocks with the appropriate associated comment ''' + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return processor = FortranTreeSitterReader() unsupported_code = """ diff --git a/src/psyclone/tests/psyir/nodes/codeblock_test.py b/src/psyclone/tests/psyir/nodes/codeblock_test.py index a17f022e4a..2d373180c9 100644 --- a/src/psyclone/tests/psyir/nodes/codeblock_test.py +++ b/src/psyclone/tests/psyir/nodes/codeblock_test.py @@ -39,6 +39,8 @@ ''' Performs py.test tests on the CodeBlock PSyIR node. ''' import pytest +import sys + from fparser.common.readfortran import FortranStringReader from psyclone.configuration import Config from psyclone.psyir.frontend.fortran import FortranReader @@ -65,8 +67,19 @@ def test_codeblock_create(): assert isinstance(cb, Fparser2CodeBlock) assert "a => b" in cb.get_fortran_lines() + # Use a different fronted value + Config.get()._frontend = "newfrontend" + with pytest.raises(InternalError) as err: + cb = CodeBlock.create("3 + 3", partial_code="expression") + assert ("The 'newfrontend' frontend does not have an associated CodeBlock " + "subclass" in str(err.value)) + # Use the treesitter frontend (the frontend doesn't support partial # expressions yet, but it gets an appropriate error) + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return Config.get()._frontend = "treesitter" cb = CodeBlock.create("program test\nend program\n") assert isinstance(cb, TreeSitterCodeBlock) @@ -77,13 +90,6 @@ def test_codeblock_create(): cb = CodeBlock.create("a => b", partial_code="pointer_assignment") assert "Syntax Error found at line 1: a => b" in str(err.value) - # Use a different fronted value - Config.get()._frontend = "newfrontend" - with pytest.raises(InternalError) as err: - cb = CodeBlock.create("3 + 3", partial_code="expression") - assert ("The 'newfrontend' frontend does not have an associated CodeBlock " - "subclass" in str(err.value)) - def test_codeblock_node_str(): ''' Check the node_str method of the Code Block class.''' @@ -184,6 +190,10 @@ def test_codeblock_get_fortran_lines(): assert "subroutine mytest" in block.get_fortran_lines() assert "end subroutine" in block.get_fortran_lines() + # TODO #3416: Skip treesitter tests below 3.10 as they're unsupported by + # treesitter. + if sys.version_info < (3, 10): + return tree = FortranTreeSitterReader().generate_parse_tree_from_source(code) block = TreeSitterCodeBlock(tree, CodeBlock.Structure.STATEMENT) assert isinstance(block.get_fortran_lines(), list) diff --git a/src/psyclone/tests/psyir/transformations/intrinsics/max2code_trans_test.py b/src/psyclone/tests/psyir/transformations/intrinsics/max2code_trans_test.py index b2dea24fac..38f07a3769 100644 --- a/src/psyclone/tests/psyir/transformations/intrinsics/max2code_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/intrinsics/max2code_trans_test.py @@ -69,8 +69,8 @@ def test_apply(fortran_reader, fortran_writer): integer :: j integer :: k integer :: l - real :: res_max - real :: tmp_max + integer :: res_max + integer :: tmp_max res_max = i tmp_max = j diff --git a/src/psyclone/tests/psyir/transformations/intrinsics/min2code_trans_test.py b/src/psyclone/tests/psyir/transformations/intrinsics/min2code_trans_test.py index 82bd85d7a2..bfc2fd90e3 100644 --- a/src/psyclone/tests/psyir/transformations/intrinsics/min2code_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/intrinsics/min2code_trans_test.py @@ -70,8 +70,8 @@ def test_apply(fortran_reader, fortran_writer): integer :: j integer :: k integer :: l - real :: res_min - real :: tmp_min + integer :: res_min + integer :: tmp_min res_min = i tmp_min = j