diff --git a/src/psyclone/psyir/symbols/generic_interface_symbol.py b/src/psyclone/psyir/symbols/generic_interface_symbol.py index e6e0fb0a23..6629dda0c7 100644 --- a/src/psyclone/psyir/symbols/generic_interface_symbol.py +++ b/src/psyclone/psyir/symbols/generic_interface_symbol.py @@ -52,7 +52,7 @@ class GenericInterfaceSymbol(RoutineSymbol): :type kwargs: unwrapped dict. ''' - RoutineInfo = namedtuple("RoutineInfo", ["symbol", "is_module"]) + RoutineInfo = namedtuple("RoutineInfo", ["symbol", "from_container"]) def __init__(self, name, routines, **kwargs): super().__init__(name, **kwargs) @@ -91,17 +91,19 @@ def routines(self, values): raise TypeError(f"A GenericInterfaceSymbol requires a list of " f"tuples describing its member routines but got: " f"'{values}'") + self._routines = [] for item in values: - if not isinstance(item, tuple) or len(item) != 2: + if not isinstance(item, tuple): raise TypeError( - f"A GenericInterfaceSymbol requires a list of 2-tuples but" - f" got: {[type(rt).__name__ for rt in values]}") - if (not isinstance(item[0], RoutineSymbol) or + f"A GenericInterfaceSymbol ('{self.name}') requires a " + f"list of tuples but got: '{type(item).__name__}'") + if (len(item) != 2 or not isinstance(item[0], RoutineSymbol) or not isinstance(item[1], bool)): raise TypeError( - f"A 2-tuple used to define a routine within the " + f"Each tuple used to define a routine within the " f"GenericInterfaceSymbol '{self.name}' must consist of a " - f"RoutineSymbol and a bool but got: {item}") + f"RoutineSymbol and a bool but got: " + f"{[type(rt).__name__ for rt in item]}") self._routines.append(self.RoutineInfo(item[0], item[1])) @property @@ -112,7 +114,7 @@ def module_routines(self): ''' result = [] for value in self._routines: - if value.is_module: + if value.from_container: result.append(value.symbol) return result @@ -124,13 +126,13 @@ def external_routines(self): ''' result = [] for value in self._routines: - if not value.is_module: + if not value.from_container: result.append(value.symbol) return result def __str__(self): return (f"{self.name}: {type(self).__name__}<{self.datatype}, " - f"routines={[rt.name for rt in self.routines]}>") + f"routines={[rt.symbol.name for rt in self.routines]}>") def copy(self): '''Create and return a copy of this object. Any references to the diff --git a/src/psyclone/psyir/symbols/symbol_table.py b/src/psyclone/psyir/symbols/symbol_table.py index 32eb0ade22..30f597847c 100644 --- a/src/psyclone/psyir/symbols/symbol_table.py +++ b/src/psyclone/psyir/symbols/symbol_table.py @@ -295,10 +295,11 @@ def deep_copy(self): for symbol in new_st.symbols: if not isinstance(symbol, GenericInterfaceSymbol): continue - new_syms = [] - for rsym in symbol.routines: - new_syms.append(new_st.lookup(rsym.name)) - symbol.routines = new_syms + new_routines = [] + for routine in symbol.routines: + new_routines.append((new_st.lookup(routine.symbol.name), + routine.from_container)) + symbol.routines = new_routines # Set the default visibility new_st._default_visibility = self.default_visibility @@ -1063,7 +1064,7 @@ def remove(self, symbol): # Check for any references to it within interfaces. for sym in self._symbols.values(): if isinstance(sym, GenericInterfaceSymbol): - if symbol in sym.routines: + if symbol in [rt.symbol for rt in sym.routines]: raise ValueError( f"Cannot remove RoutineSymbol '{symbol.name}' " f"because it is referenced in interface " diff --git a/src/psyclone/tests/psyir/backend/fortran_gen_decls_test.py b/src/psyclone/tests/psyir/backend/fortran_gen_decls_test.py index 2a99dfc963..358b4de9f5 100644 --- a/src/psyclone/tests/psyir/backend/fortran_gen_decls_test.py +++ b/src/psyclone/tests/psyir/backend/fortran_gen_decls_test.py @@ -319,10 +319,11 @@ def test_procedure_interface(fortran_reader, fortran_writer): declaration from a GenericInterfaceSymbol. ''' symbol_table = SymbolTable() - isub = GenericInterfaceSymbol("subx", [RoutineSymbol("sub1"), - RoutineSymbol("sub2")]) + isub = GenericInterfaceSymbol("subx", [(RoutineSymbol("sub1"), False), + (RoutineSymbol("sub2"), True)]) symbol_table.add(isub) out = fortran_writer.gen_decls(symbol_table) assert "interface subx" in out - assert "procedure :: sub1, sub2" in out + assert "procedure :: sub1" in out + assert "module procedure :: sub2" in out assert "end interface subx" in out diff --git a/src/psyclone/tests/psyir/backend/fortran_unknown_declns_test.py b/src/psyclone/tests/psyir/backend/fortran_unknown_declns_test.py index 1a3af9e765..3759c0a2d3 100644 --- a/src/psyclone/tests/psyir/backend/fortran_unknown_declns_test.py +++ b/src/psyclone/tests/psyir/backend/fortran_unknown_declns_test.py @@ -125,8 +125,8 @@ def __str__(self): container.symbol_table.add(RoutineSymbol("eos", OtherType("some code"))) with pytest.raises(InternalError) as err: fortran_writer.gen_decls(container.symbol_table) - assert ("Symbol 'eos' is a RoutineSymbol which is not imported nor an " - "interface (UnknownFortranType). This is already implicitly " + assert ("Symbol 'eos' is a RoutineSymbol which is not imported or of " + "UnknownFortranType. This is already implicitly " "declared by the routine itself and should not be provided " "to 'gen_vardecl'." in str(err.value)) diff --git a/src/psyclone/tests/psyir/frontend/fparser2_select_case_test.py b/src/psyclone/tests/psyir/frontend/fparser2_select_case_test.py index 7924a3849f..78597bd61a 100644 --- a/src/psyclone/tests/psyir/frontend/fparser2_select_case_test.py +++ b/src/psyclone/tests/psyir/frontend/fparser2_select_case_test.py @@ -461,7 +461,8 @@ def has_cmp_interface(code): # Check that the generic interface in in the code assert '''interface psyclone_internal_cmp procedure :: psyclone_cmp_int, psyclone_cmp_logical, psyclone_cmp_char - end interface psyclone_internal_cmp''' in code + end interface psyclone_internal_cmp + private psyclone_internal_cmp''' in code # Check that the integer implementation is in the code assert '''function psyclone_cmp_int(op1, op2) diff --git a/src/psyclone/tests/psyir/symbols/generic_interface_symbol_test.py b/src/psyclone/tests/psyir/symbols/generic_interface_symbol_test.py index e3ebb31b6b..d9e1d1cae8 100644 --- a/src/psyclone/tests/psyir/symbols/generic_interface_symbol_test.py +++ b/src/psyclone/tests/psyir/symbols/generic_interface_symbol_test.py @@ -58,10 +58,19 @@ def test_gis_constructor(): acorn = RoutineSymbol("acorn") with pytest.raises(TypeError) as err: _ = GenericInterfaceSymbol("oak", [acorn, "sycamore"]) - assert ("of RoutineSymbols but got: ['RoutineSymbol', 'str']" in + assert ("GenericInterfaceSymbol ('oak') requires a list of tuples but " + "got: 'RoutineSymbol'" in str(err.value)) + with pytest.raises(TypeError) as err: + _ = GenericInterfaceSymbol("oak", [(acorn, False), + (acorn, False, False)]) + assert ("Each tuple used to define a routine within the " + "GenericInterfaceSymbol 'oak' must consist of a RoutineSymbol and " + "a bool but got: ['RoutineSymbol', 'bool', 'bool']" in str(err.value)) - oak = GenericInterfaceSymbol("oak", [acorn]) - assert oak.routines == [acorn] + oak = GenericInterfaceSymbol("oak", [(acorn, False)]) + assert len(oak.routines) == 1 + assert oak.routines[0].symbol is acorn + assert oak.routines[0].from_container is False def test_gis_typedsymbol_keywords(): @@ -69,7 +78,7 @@ def test_gis_typedsymbol_keywords(): Test that keyword arguments to the constructor are passed through to the TypedSymbol constructor. ''' - walnut = GenericInterfaceSymbol("walnut", [RoutineSymbol("nut")], + walnut = GenericInterfaceSymbol("walnut", [(RoutineSymbol("nut"), True)], datatype=INTEGER_TYPE) assert walnut.datatype == INTEGER_TYPE @@ -80,7 +89,7 @@ def test_gis_str(): ''' ash = RoutineSymbol("ash") holly = RoutineSymbol("holly") - coppice = GenericInterfaceSymbol("coppice", [ash, holly]) + coppice = GenericInterfaceSymbol("coppice", [(ash, True), (holly, False)]) assert str(coppice) == ("coppice: GenericInterfaceSymbol") @@ -91,10 +100,11 @@ def test_gis_copy(): ''' ash = RoutineSymbol("ash") holly = RoutineSymbol("holly") - coppice = GenericInterfaceSymbol("coppice", [ash, holly]) + coppice = GenericInterfaceSymbol("coppice", [(ash, True), (holly, False)]) spinney = coppice.copy() assert isinstance(spinney, GenericInterfaceSymbol) assert spinney is not coppice assert len(spinney.routines) == 2 - assert ash in spinney.routines - assert holly in spinney.routines + rsyms = [item.symbol for item in spinney.routines] + assert ash in rsyms + assert holly in rsyms diff --git a/src/psyclone/tests/psyir/symbols/symbol_table_test.py b/src/psyclone/tests/psyir/symbols/symbol_table_test.py index 24c9dee541..ddb2469471 100644 --- a/src/psyclone/tests/psyir/symbols/symbol_table_test.py +++ b/src/psyclone/tests/psyir/symbols/symbol_table_test.py @@ -1663,7 +1663,7 @@ def test_deep_copy(): symtab.add(sym3) symtab.specify_argument_list([sym1]) rsym = symbols.RoutineSymbol("my_sub") - gisym = symbols.GenericInterfaceSymbol("generic_sub", [rsym]) + gisym = symbols.GenericInterfaceSymbol("generic_sub", [(rsym, False)]) symtab.add(rsym) symtab.add(gisym)