From b588404666c18d1d64536f626a72475d62c26c85 Mon Sep 17 00:00:00 2001 From: Andrew Porter Date: Mon, 8 Jan 2024 15:52:09 +0000 Subject: [PATCH] #924 add new Node.get_container_defintion() and delete unused code --- src/psyclone/psyir/nodes/call.py | 38 +- src/psyclone/psyir/nodes/container.py | 10 +- src/psyclone/psyir/nodes/node.py | 27 ++ src/psyclone/psyir/symbols/containersymbol.py | 35 -- .../psyir/transformations/inline_trans.py | 150 -------- .../tests/psyir/nodes/container_test.py | 127 ++++++- .../transformations/inline_trans_test.py | 324 ------------------ 7 files changed, 168 insertions(+), 543 deletions(-) diff --git a/src/psyclone/psyir/nodes/call.py b/src/psyclone/psyir/nodes/call.py index cde1e4b26f..71264a79b5 100644 --- a/src/psyclone/psyir/nodes/call.py +++ b/src/psyclone/psyir/nodes/call.py @@ -455,8 +455,6 @@ def _location_txt(node): last_line = out_lines[idx] return f"code:\n'{out_lines[0]}\n...\n{last_line}'" - #import pdb; pdb.set_trace() - local_containers = self.root.walk(Container, stop_type=Routine) rsym = self.routine if rsym.is_unresolved: @@ -478,20 +476,10 @@ def _location_txt(node): for container_symbol in current_table.containersymbols: if container_symbol.wildcard_import: wildcard_names.append(container_symbol.name) - for local in local_containers: - if container_symbol.name == local.name: - container = local - break - else: - # The Container isn't defined locally. - try: - container = container_symbol.container - except SymbolError: - # Failed to find the container source. - # TODO #924 this would be much better as a - # FileNotFoundError. - continue - # TODO this needs to support returning multiple routines + container = self.get_container_definition( + container_symbol) + if not container: + continue routine = container.get_routine_definition(rsym.name) if routine: return [routine] @@ -513,14 +501,12 @@ def _location_txt(node): cursor = rsym while cursor.is_import: csym = cursor.interface.container_symbol - for local in local_containers: - if local.name == csym.name: - container = local - break - else: - # If necessary, this will search for and process the source - # file defining the container. - container = csym.container + container = self.get_container_definition(csym) + if not container: + raise NotImplementedError( + f"RoutineSymbol '{rsym.name}' is imported from " + f"Container '{csym.name}' but the source defining " + f"that container could not be found.") imported_sym = container.symbol_table.lookup(cursor.name) if imported_sym.visibility != Symbol.Visibility.PUBLIC: # The required Symbol must be shadowed with a PRIVATE @@ -556,10 +542,6 @@ def _location_txt(node): routine = container.get_routine_definition(rsym.name) if routine: return [routine] - #for routine in root_node.walk(Routine, stop_type=Routine): - # if routine.name.lower() == rsym.name.lower(): - # kernel_schedule = routine - # return [kernel_schedule] raise SymbolError( f"Failed to find a Routine named '{rsym.name}' in " diff --git a/src/psyclone/psyir/nodes/container.py b/src/psyclone/psyir/nodes/container.py index 68fd528f6c..ae174e200e 100644 --- a/src/psyclone/psyir/nodes/container.py +++ b/src/psyclone/psyir/nodes/container.py @@ -191,14 +191,20 @@ def get_routine_definition(self, name): routine_sym = table.lookup(rname) if routine_sym.is_import: child_cntr_sym = routine_sym.interface.container_symbol - return child_cntr_sym.get_routine_definition(rname) + # Find the definition of the container. + container = self.get_container_definition(child_cntr_sym) + if not container: + return None + return container.get_routine_definition(rname) except KeyError: pass # Look in any wildcard imports. for child_cntr_sym in table.containersymbols: if child_cntr_sym.wildcard_import: - result = child_cntr_sym.get_routine_definition(rname) + # Find the definition of the container. + container = self.get_container_definition(child_cntr_sym) + result = container.get_routine_definition(rname) if result: return result # The required Routine was not found in the Container. diff --git a/src/psyclone/psyir/nodes/node.py b/src/psyclone/psyir/nodes/node.py index fd28128275..3a77c15a95 100644 --- a/src/psyclone/psyir/nodes/node.py +++ b/src/psyclone/psyir/nodes/node.py @@ -1698,6 +1698,33 @@ def path_from(self, ancestor): result_list.reverse() return result_list + def get_container_definition(self, csym): + ''' + :param csym: the container to search for. + :type csym: :py:class:`psyclone.psyir.symbols.ContainerSymbol` + + :returns: the PSyIR of the specified Container or None if not found. + :rtype: :py:class:`psyclone.psyir.nodes.Container` | NoneType + + ''' + # TODO should this be replaced by the ModuleManager? + lowered_name = csym.name.lower() + from psyclone.psyir.nodes.container import Container + from psyclone.psyir.nodes.routine import Routine + local_containers = self.root.walk(Container, stop_type=Routine) + for local in local_containers: + if lowered_name == local.name.lower(): + return local + + # The Container isn't defined locally. + try: + return csym.container + except SymbolError: + # Failed to find the container source. + # TODO #924 this would be much better as a + # FileNotFoundError. + return None + # For automatic documentation generation # TODO #913 the 'colored' routine shouldn't be in this module. diff --git a/src/psyclone/psyir/symbols/containersymbol.py b/src/psyclone/psyir/symbols/containersymbol.py index 6a7ccc30a8..7cd34b1c0f 100644 --- a/src/psyclone/psyir/symbols/containersymbol.py +++ b/src/psyclone/psyir/symbols/containersymbol.py @@ -163,41 +163,6 @@ def wildcard_import(self, value): f"'{type(value).__name__}'") self._has_wildcard_import = value - def old_get_routine_definition(self, name): - ''' - ''' - rname = name.lower() - # Get the container definition. Imports it if necessary. - cntr = self.container - from psyclone.psyir.nodes.routine import Routine - for node in cntr.children: - if isinstance(node, Routine) and node.name.lower() == rname: - # Check this routine is public - routine_sym = cntr.symbol_table.lookup(node.name) - if routine_sym.visibility == Symbol.Visibility.PUBLIC: - return node - # The Container does not contain the expected Routine or the - # Routine is not public. - - # Look in the import that names the routine if there is one. - table = cntr.symbol_table - try: - routine_sym = table.lookup(rname) - if routine_sym.is_import: - child_cntr_sym = routine_sym.interface.container_symbol - return child_cntr_sym.get_routine_definition(rname) - except KeyError: - pass - - # Look in any wildcard imports. - for child_cntr_sym in table.containersymbols: - if child_cntr_sym.wildcard_import: - result = child_cntr_sym.get_routine_definition(rname) - if result: - return result - # The required Routine was not found in the Container. - return None - class ContainerSymbolInterface(SymbolInterface): ''' Abstract implementation of the ContainerSymbol Interface ''' diff --git a/src/psyclone/psyir/transformations/inline_trans.py b/src/psyclone/psyir/transformations/inline_trans.py index 6e50efeed3..8f1485da97 100644 --- a/src/psyclone/psyir/transformations/inline_trans.py +++ b/src/psyclone/psyir/transformations/inline_trans.py @@ -840,156 +840,6 @@ def validate(self, node, options=None): f"with a non-unit stride: " f"'{actual_arg.debug_string()}' (TODO #1646)")) - @staticmethod - def _find_routine(call_node): - '''Searches for the definition of the routine that is being called by - the supplied Call. - - :param call_node: the Call that is to be inlined. - :type call_node: :py:class:`psyclone.psyir.nodes.Call` - - :returns: the PSyIR for the target routine. - :rtype: :py:class:`psyclone.psyir.nodes.Routine` - - :raises TransformationError: if the routine definition cannot be found. - - ''' - # TODO remove this routine altogether! - try: - callees = call_node.get_callees() - return callees[0] - except (NotImplementedError, SymbolError) as err: - raise TransformationError( - f"Failed to find the source code of the routine " - f"'{call_node.routine.name}': {err}") from err - - name = call_node.routine.name - routine_sym = call_node.routine - - if routine_sym.is_modulevar: - table = routine_sym.find_symbol_table(call_node) - for routine in table.node.walk(Routine): - if routine.name.lower() == name.lower(): - return routine - raise TransformationError( - f"Failed to find the source code of the local routine " - f"'{routine_sym.name}' - it is probably in a CodeBlock.") - - if routine_sym.is_unresolved: - - # First check for any wildcard imports and see if they can - # be used to resolve the symbol. - wildcard_names = [] - current_table = call_node.scope.symbol_table - while current_table: - for container_symbol in current_table.containersymbols: - if container_symbol.wildcard_import: - wildcard_names.append(container_symbol.name) - routine = InlineTrans._find_routine_in_container( - call_node, container_symbol) - if routine: - return routine - current_table = current_table.parent_symbol_table() - - # Next check for any "raw" Routines, i.e. ones that are not - # in a Container. Such Routines would exist in the PSyIR - # as a child of a FileContainer (if the PSyIR contains a - # FileContainer). Note, if the PSyIR does contain a - # FileContainer, it will be the root node of the PSyIR. - for routine in call_node.root.children: - if (isinstance(routine, Routine) and - routine.name.lower() == name.lower()): - return routine - raise TransformationError( - f"Failed to find the source code of the unresolved " - f"routine '{name}' after trying wildcard imports from " - f"{wildcard_names} and all routines that are not in " - f"containers.") - - if routine_sym.is_import: - container_symbol = routine_sym.interface.container_symbol - routine = InlineTrans._find_routine_in_container( - call_node, container_symbol) - if routine: - return routine - raise TransformationError( - f"Failed to find the source for routine '{routine_sym.name}' " - f"imported from '{container_symbol.name}' and therefore " - f"cannot inline it.") - - if isinstance(routine_sym.datatype, UnknownType): - raise TransformationError( - f"Failed to find the source for routine '{routine_sym.name}' " - f"which is of type '{routine_sym.datatype}'. This indicates " - f"that it corresponds to a generic interface and inlining " - f"such a routine is not yet implemented - TODO #924") - - raise InternalError( - f"Routine Symbol '{routine_sym.name}' is not local, " - f"unresolved or imported.") - - @staticmethod - def _find_routine_in_container(call_node, container_symbol): - '''Searches for the definition of a routine that is being called by - the supplied Call. If present, this routine must exist within a - container specified by the supplied container symbol. - - :param call_node: the Call that is to be inlined. - :type call_node: :py:class:`psyclone.psyir.nodes.Call` - - :param container_symbol: the symbol of the container to search. - :type container_symbol: \ - :py:class:`psyclone.psyir.symbols.ContainerSymbol` - - :returns: the PSyIR for the target routine, if found. - :rtype: Optional[:py:class:`psyclone.psyir.nodes.Routine`] - - ''' - # The required Routine will exist within a Container and - # that Container could exist in the PSyIR as a child of a - # FileContainer (if the PSyIR contains a - # FileContainer). If the PSyIR does contain a - # FileContainer, it will be the root node of the PSyIR. - call_routine_sym = call_node.routine - for container in call_node.root.children: - if (isinstance(container, Container) and - container.name.lower() == container_symbol.name.lower()): - for routine in container.children: - if (isinstance(routine, Routine) and - routine.name.lower() == - call_routine_sym.name.lower()): - # Check this routine is public - routine_sym = container.symbol_table.lookup( - routine.name) - if routine_sym.visibility == Symbol.Visibility.PUBLIC: - return routine - # The Container has been found but it does not contain - # the expected Routine or the Routine is not public. - - # Look in the import that names the routine if there is one. - table = container.symbol_table - try: - routine_sym = table.lookup(call_routine_sym.name) - if routine_sym.is_import: - child_container_symbol = \ - routine_sym.interface.container_symbol - return (InlineTrans._find_routine_in_container( - call_node, child_container_symbol)) - except KeyError: - pass - - # Look in any wildcard imports. - for child_container_symbol in table.containersymbols: - if child_container_symbol.wildcard_import: - result = InlineTrans._find_routine_in_container( - call_node, child_container_symbol) - if result: - return result - # The required Symbol was not found in the Container. - return None - # The specified Container was not found in the PSyIR. - return None - # For AutoAPI auto-documentation generation. __all__ = ["InlineTrans"] diff --git a/src/psyclone/tests/psyir/nodes/container_test.py b/src/psyclone/tests/psyir/nodes/container_test.py index edf2865552..a86f025929 100644 --- a/src/psyclone/tests/psyir/nodes/container_test.py +++ b/src/psyclone/tests/psyir/nodes/container_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2019-2022, Science and Technology Facilities Council. +# Copyright (c) 2019-2024, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -38,10 +38,9 @@ ''' Performs py.test tests on the Container PSyIR node. ''' -from __future__ import absolute_import import pytest -from psyclone.psyir.nodes import Container, Return, KernelSchedule, \ - FileContainer +from psyclone.psyir.nodes import (Call, Container, KernelSchedule, + FileContainer, Return, Routine) from psyclone.psyir.symbols import SymbolTable, DataSymbol, REAL_SINGLE_TYPE from psyclone.errors import GenerationError from psyclone.psyir.backend.fortran import FortranWriter @@ -180,3 +179,123 @@ def test_container_children_validation(): assert ("Item 'Return' can't be child 1 of 'Container'. The valid format" " is: '[Container | Routine | CodeBlock]*'." "" in str(excinfo.value)) + + +# _find_routine_in_container + +CALL_IN_SUB_USE = ( + "subroutine run_it()\n" + " use inline_mod, only : sub\n" + " real :: a\n" + " call sub(a)\n" + "end subroutine run_it\n") +CALL_IN_SUB = CALL_IN_SUB_USE.replace( + " use inline_mod, only : sub\n", "") +SUB = ( + "subroutine sub(x)\n" + " real :: x\n" + " x = 1.0\n" + "end subroutine sub\n") +SUB_IN_MODULE = ( + f"module inline_mod\n" + f"contains\n" + f"{SUB}" + f"end module inline_mod\n") + + +def test_get_routine_definition_routine_not_found(fortran_reader): + '''Test that None is returned when the required Routine is not found + in the Container associated with the supplied container symbol, as + it does not exist. + + ''' + code = ( + "module inline_mod\n" + "end module inline_mod\n") + psyir = fortran_reader.psyir_from_source(code) + container = psyir.children[0] + result = container.get_routine_definition("missing") + assert result is None + + +def test_get_routine_definition_recurse_named(fortran_reader): + '''Test that when a container does not contain the required routine, + any imported containers within this container are also + searched. In this case the test is for a container within the + original container that explicitly names the routine. The PSyIR of + the routine is returned when it is found in the second container. + + ''' + code = ( + f"{CALL_IN_SUB_USE}" + f"module inline_mod\n" + f"use inline_mod2, only : sub\n" + f"end module inline_mod\n" + f"module inline_mod2\n" + f"contains\n" + f"{SUB}\n" + f"end module inline_mod2\n") + psyir = fortran_reader.psyir_from_source(code) + container = psyir.walk(Container)[1] + result = container.get_routine_definition("sub") + assert isinstance(result, Routine) + assert result.name == "sub" + + +def test_get_routine_definition_recurse_wildcard(fortran_reader): + '''Test that when a container does not contain the required routine, + any imported containers within this container are also + searched. In this case the test is for a wildcard container within + the original container. The PSyIR of the routine is returned when + it is found in the second container. + + ''' + code = ( + f"{CALL_IN_SUB_USE}" + f"module inline_mod\n" + f"use inline_mod2\n" + f"end module inline_mod\n" + f"module inline_mod2\n" + f"contains\n" + f"{SUB}\n" + f"end module inline_mod2\n") + psyir = fortran_reader.psyir_from_source(code) + call_node = psyir.walk(Call)[0] + container = psyir.get_container_definition(call_node.routine.interface.container_symbol) + result = container.get_routine_definition(call_node.routine.name) + assert isinstance(result, Routine) + assert result.name == "sub" + + +def test_find_routine_in_container_private_routine_not_found(fortran_reader): + '''Test that None is returned when the required Routine is not found + in the Container associated with the supplied container symbol, as + it is private. This situation should not arise as it is invalid to + try to import a private routine. However, there are currrently no + checks for this when creating PSyIR. + + ''' + private_sub_in_module = SUB_IN_MODULE.replace( + "contains\n", " private :: sub\ncontains\n") + code = f"{private_sub_in_module}{CALL_IN_SUB_USE}" + psyir = fortran_reader.psyir_from_source(code) + call_node = psyir.walk(Call)[0] + container = psyir.get_container_definition( + call_node.routine.interface.container_symbol) + result = container.get_routine_definition(call_node.routine.name) + assert result is None + + +def test_find_routine_in_container(fortran_reader): + '''Test that the PSyIR of the Routine is returned when it is found + in the Container associated with the supplied container symbol. + + ''' + code = f"{SUB_IN_MODULE}{CALL_IN_SUB_USE}" + psyir = fortran_reader.psyir_from_source(code) + call_node = psyir.walk(Call)[0] + container = psyir.get_container_definition( + call_node.routine.interface.container_symbol) + result = container.get_routine_definition(call_node.routine.name) + assert isinstance(result, Routine) + assert result.name == "sub" diff --git a/src/psyclone/tests/psyir/transformations/inline_trans_test.py b/src/psyclone/tests/psyir/transformations/inline_trans_test.py index d9b8ef17e3..555074e3ce 100644 --- a/src/psyclone/tests/psyir/transformations/inline_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/inline_trans_test.py @@ -2088,330 +2088,6 @@ def test_validate_named_arg(fortran_reader): f"end module inline_mod\n") -# _find_routine - -def test_find_routine_local(fortran_reader): - '''Test that the PSyIR of the Routine is returned when it is local to - the module associated with the call. - - ''' - code = ( - f"module test_mod\n" - f"contains\n" - f"{CALL_IN_SUB}" - f"{SUB}" - f"end module test_mod\n") - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine(call) - assert call.routine.is_modulevar - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_missing_exception(fortran_reader): - '''Test that the expected exception is raised if the Call's Routine - symbol has a module interface but the Routine can't be found in the - PSyIR. - - ''' - code = ( - f"module test_mod\n" - f"contains\n" - f"{CALL_IN_SUB}" - f"{SUB}" - f"end module test_mod\n") - psyir = fortran_reader.psyir_from_source(code) - # remove the subroutine 'sub' from the PSyIR tree. - psyir.children[0].children[1].detach() - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_modulevar - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find a Routine named 'sub' in Container 'test_mod'. " - "This is normally because the routine is within a CodeBlock." in - str(info.value)) - - -def test_find_routine_unresolved_wildcard(fortran_reader): - '''Test that the routine can be found via a wildcard use statement.''' - - wildcard_use = CALL_IN_SUB_USE.replace(", only : sub", "") - code = f"{wildcard_use}{SUB_IN_MODULE}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_unresolved - result = inline_trans._find_routine(call) - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_unresolved(fortran_reader): - '''Test that the routine can be found when there are no use statements - and there is a 'raw' subroutine. - - ''' - code = f"{CALL_IN_SUB}{SUB}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_unresolved - result = inline_trans._find_routine(call) - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_raw_to_module_exception(fortran_reader): - '''Test that the routine is not found and an exception is raised if - there is no use statement and the code for another routine with - the same name is specified within a module. - - ''' - code = f"{CALL_IN_SUB}{SUB_IN_MODULE}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_unresolved - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find the source code of the unresolved routine 'sub' " - "after trying wildcard imports from [] and all routines that are " - "not in containers." in str(info.value)) - - -def test_find_routine_unresolved_exception(fortran_reader): - '''Test that the expected exception is raised if the routine is - unresolved and can't be found in any wildcard imports or any 'raw' - subroutines. - - ''' - wildcard_use = CALL_IN_SUB_USE.replace(", only : sub", "") - code = ( - f"{wildcard_use}" - f"module inline_mod\n" - f"end module inline_mod\n" - f"subroutine sub2()\n" - f"end subroutine sub2\n") - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_unresolved - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find the source code of the unresolved routine 'sub' " - "after trying wildcard imports from ['inline_mod'] and all " - "routines that are not in containers." in str(info.value)) - - -def test_find_routine_import(fortran_reader): - '''Test that the routine can be found when there is a use statement - and the subroutine can be found in the associated module. - - ''' - code = f"{CALL_IN_SUB_USE}{SUB_IN_MODULE}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_import - result = inline_trans._find_routine(call) - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_import_exception(fortran_reader): - '''Test that the routine raises the expected exception if the imported - module can't be found. - - ''' - code = f"{CALL_IN_SUB_USE}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_import - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find the source code of the routine 'sub':" in - str(info.value)) - assert ("Module 'inline_mod' (expected to be found in 'inline_mod" in - str(info.value)) - - -def test_find_routine_module_to_raw_exception(fortran_reader): - '''Test that the routine raises the expected exception if the call - imports the routine and the routine can't be found, even in the - presence of a 'raw' subroutine with the same name. - - ''' - code = f"{CALL_IN_SUB_USE}{SUB}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - inline_trans = InlineTrans() - assert call.routine.is_import - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find the source code of the routine 'sub':" in - str(info.value)) - assert ("Module 'inline_mod' (expected to be found in 'inline_mod." in - str(info.value)) - - -def test_find_routine_exception(fortran_reader, monkeypatch): - '''Test that the routine raises the expected exception if the call's - routine symbol is not local, unresolved or import. Need to - monkeypatch as this exception is not something that should happen. - - ''' - code = f"{CALL_IN_SUB}" - psyir = fortran_reader.psyir_from_source(code) - call = psyir.walk(Call)[0] - # Set the interface to None so it is not local, unresolved or import. - monkeypatch.setattr(call.routine, "_interface", None) - inline_trans = InlineTrans() - with pytest.raises(TransformationError) as info: - _ = inline_trans._find_routine(call) - assert ("Failed to find the source code of the routine 'sub'" - in str(info.value)) - - -# _find_routine_in_container - -def test_find_routine_in_container_no_container(fortran_reader): - '''Test that None is returned when the Container associated with the - supplied container symbol is not found in the PSyIR. - - ''' - psyir = fortran_reader.psyir_from_source(CALL_IN_SUB_USE) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert result is None - - -def test_find_routine_in_container_no_file_container(fortran_reader): - '''Test that None is returned when the Container associated with the - supplied container symbol is not found in the PSyIR and the root - is not a FileContainer. - - ''' - psyir = fortran_reader.psyir_from_source(CALL_IN_SUB_USE) - # Remove the FileContainer from the PSyIR tree - psyir = psyir.children[0] - psyir.detach() - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert result is None - - -def test_find_routine_in_container_routine_not_found(fortran_reader): - '''Test that None is returned when the required Routine is not found - in the Container associated with the supplied container symbol, as - it does not exist. - - ''' - code = ( - f"module inline_mod\n" - f"end module inline_mod\n" - f"{CALL_IN_SUB_USE}") - psyir = fortran_reader.psyir_from_source(code) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert result is None - - -def test_find_routine_in_container_recurse_named(fortran_reader): - '''Test that when a container does not contain the required routine, - any imported containers within this container are also - searched. In this case the test is for a container within the - original container that explicitly names the routine. The PSyIR of - the routine is returned when it is found in the second container. - - ''' - code = ( - f"{CALL_IN_SUB_USE}" - f"module inline_mod\n" - f"use inline_mod2, only : sub\n" - f"end module inline_mod\n" - f"module inline_mod2\n" - f"contains\n" - f"{SUB}\n" - f"end module inline_mod2\n") - psyir = fortran_reader.psyir_from_source(code) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_in_container_recurse_wildcard(fortran_reader): - '''Test that when a container does not contain the required routine, - any imported containers within this container are also - searched. In this case the test is for a wildcard container within - the original container. The PSyIR of the routine is returned when - it is found in the second container. - - ''' - code = ( - f"{CALL_IN_SUB_USE}" - f"module inline_mod\n" - f"use inline_mod2\n" - f"end module inline_mod\n" - f"module inline_mod2\n" - f"contains\n" - f"{SUB}\n" - f"end module inline_mod2\n") - psyir = fortran_reader.psyir_from_source(code) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert isinstance(result, Routine) - assert result.name == "sub" - - -def test_find_routine_in_container_private_routine_not_found(fortran_reader): - '''Test that None is returned when the required Routine is not found - in the Container associated with the supplied container symbol, as - it is private. This situation should not arise as it is invalid to - try to import a private routine. However, there are currrently no - checks for this when creating PSyIR. - - ''' - private_sub_in_module = SUB_IN_MODULE.replace( - "contains\n", " private :: sub\ncontains\n") - code = f"{private_sub_in_module}{CALL_IN_SUB_USE}" - psyir = fortran_reader.psyir_from_source(code) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert result is None - - -def test_find_routine_in_container(fortran_reader): - '''Test that the PSyIR of the Routine is returned when it is found - in the Container associated with the supplied container symbol. - - ''' - code = f"{SUB_IN_MODULE}{CALL_IN_SUB_USE}" - psyir = fortran_reader.psyir_from_source(code) - call_node = psyir.walk(Call)[0] - inline_trans = InlineTrans() - result = inline_trans._find_routine_in_container( - call_node, call_node.routine.interface.container_symbol) - assert isinstance(result, Routine) - assert result.name == "sub" - - def test_apply_merges_symbol_table_with_routine(fortran_reader): ''' Check that the apply method merges the inlined function's symbol table to