Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduler: Fix handling of external module procedures #263

Merged
merged 2 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions loki/batch/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -1123,11 +1123,12 @@ def get_or_create_item(self, item_cls, item_name, scope_name, config=None):
return self.item_cache[item_name]

item_conf = config.create_item_config(item_name) if config else None
if scope_name not in self.item_cache:
scope_item = self.item_cache.get(scope_name)
if scope_item is None or isinstance(scope_item, ExternalItem):
warning(f'Module {scope_name} not found in self.item_cache. Marking {item_name} as an external dependency')
item = ExternalItem(item_name, source=None, config=item_conf, origin_cls=item_cls)
else:
source = self.item_cache[scope_name].source
source = scope_item.source
item = item_cls(item_name, source=source, config=item_conf)
self.item_cache[item_name] = item
return item
Expand Down
4 changes: 2 additions & 2 deletions loki/frontend/regex.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ def __init__(self):
r'^module[ \t]+(?P<name>\w+)\b.*?$'
r'(?P<spec>.*?)'
r'(?P<contains>^contains\n(?:'
r'(?:[ \t\w()]*?subroutine.*?^end[ \t]*subroutine\b(?:[ \t]\w+)?\n)|'
r'(?:[ \t\w()]*?function.*?^end[ \t]*function\b(?:[ \t]\w+)?\n)|'
r'(?:[ \t\w()=]*?subroutine.*?^end[ \t]*subroutine\b(?:[ \t]\w+)?\n)|'
r'(?:[ \t\w()=]*?function.*?^end[ \t]*function\b(?:[ \t]\w+)?\n)|'
r'(?:^#\w+.*?\n)'
r')*)?'
r'^end[ \t]*module\b(?:[ \t](?P=name))?',
Expand Down
44 changes: 44 additions & 0 deletions tests/test_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,50 @@ def test_procedure_item_with_config2(here, disable):
assert item.targets == ('t_mod', 't', 'nt1', 'header_mod', 'arg%proc', 'arg%no%way')


@pytest.mark.parametrize('enable_imports', [False, True])
def test_procedure_item_external_item(enable_imports, default_config):
"""
Test that dependencies to external module procedures are marked as external item
"""
fcode = """
subroutine procedure_item_external_item
use external_mod, only: external_proc, unused_external_proc, external_type, external_var
implicit none
type(external_type) :: my_type

call external_proc(1)

my_type%my_val = external_var
end subroutine procedure_item_external_item
"""
workdir = gettempdir()/'test_procedure_item_external_item'
workdir.mkdir(exist_ok=True)
filepath = workdir/'procedure_item_external_item.F90'
filepath.write_text(fcode)

default_config['default']['enable_imports'] = enable_imports
scheduler_config = SchedulerConfig.from_dict(default_config)
item = get_item(
ProcedureItem, filepath, '#procedure_item_external_item',
RegexParserClass.ProgramUnitClass, scheduler_config
)
item_factory = ItemFactory()
item_factory.item_cache[item.name] = item
items = item.create_dependency_items(item_factory=item_factory, config=scheduler_config)

# NB: dependencies to imported symbols are not added as external items because it would be impossible
# to determine their type. Instead, the external module is marked as a dependency, regardless if
# imports are enabled or not.
# However, the external procedure with a call statement is recognized as an external procedure
# and therefore included in the dependency tree.
assert items == ('external_mod', 'external_mod#external_proc')
assert all(isinstance(it, ExternalItem) for it in items)
assert [it.origin_cls for it in items] == [ModuleItem, ProcedureItem]

filepath.unlink(missing_ok=True)
workdir.rmdir()


def test_typedef_item(here):
proj = here/'sources/projBatch'

Expand Down
7 changes: 4 additions & 3 deletions tests/test_frontends.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,9 @@ def test_regex_module_from_source():
"""
fcode = """
module some_module
implicit none
use foobar
implicit none
integer, parameter :: k = selected_int_kind(5)
contains
subroutine module_routine
integer m
Expand All @@ -481,9 +482,9 @@ def test_regex_module_from_source():
call routine_b(m, 6)
end subroutine module_routine

function module_function(n)
integer(kind=k) function module_function(n)
integer n
n = 3
module_function = n + 2
end function module_function
end module some_module
""".strip()
Expand Down
Loading