Repository: stfc/PSyclone

Issue:
[WW3] sub-string of character string causes crash
Asif has reported that the WW3 code uses a character variable:

      CHARACTER(256)          :: LINE, TEST
    100 CONTINUE
      ! read line
      READ ( NDSI, 900, END=800, ERR=801, IOSTAT=IERR, IOMSG=MSG ) LINE
      ! leading blanks removed and placed on the right
      TEST = ADJUSTL ( LINE )
      IF ( TEST(1:1).EQ.CHCKC .OR. LEN_TRIM(TEST).EQ.0 ) THEN

and PSyclone falls over in `ArrayMixin.is_lower_bound` when examinging `TEST(1:1)` because it assumes it is of ArrayType whereas it is in fact of UnknownFortranType (because we don't support Character variables).

Discussion:

Patch:
diff --git a/changelog b/changelog
index 2698fe9a5..4dff2aabb 100644
--- a/changelog
+++ b/changelog
@@ -134,12 +134,14 @@
 	to query the resulting datatype of a PSyIR subtree.
 
 	49) PR #1869 for #1868. Extend PSyAD to make use of the
-        Reference2ArrayRangeTrans.
+	Reference2ArrayRangeTrans.
 
 	50) PR #1880 for #1865. Improves support for function calls in the
 	PSyIR by ensuring the associated RoutineSymbol has the correct
 	datatype.
 
+	51) PR #1894 for #1893. Fix bug in is_upper/lower_bound for UnknownTypes.
+
 release 2.3.1 17th of June 2022
 
 	1) PR #1747 for #1720. Adds support for If blocks to PSyAD.
diff --git a/src/psyclone/psyir/nodes/array_mixin.py b/src/psyclone/psyir/nodes/array_mixin.py
index 69e421fba..11c1e0f0c 100644
--- a/src/psyclone/psyir/nodes/array_mixin.py
+++ b/src/psyclone/psyir/nodes/array_mixin.py
@@ -96,7 +96,7 @@ class ArrayMixin(metaclass=abc.ABCMeta):
         :rtype: tuple(:py:class:`psyclone.core.Signature`, list of \
             lists of indices)
         '''
-        sig, _ = super(ArrayMixin, self).get_signature_and_indices()
+        sig, _ = super().get_signature_and_indices()
         return (sig, [self.indices[:]])
 
     def _validate_index(self, index):
@@ -152,6 +152,10 @@ class ArrayMixin(metaclass=abc.ABCMeta):
             try:
                 symbol = self.scope.symbol_table.lookup(self.name)
                 datatype = symbol.datatype
+                # Check that the symbol is of ArrayType. (It may be of
+                # UnknownFortranType if the symbol is of e.g. character type.)
+                if not isinstance(datatype, ArrayType):
+                    return False
                 shape = datatype.shape
                 array_bounds = shape[index]
                 if (isinstance(array_bounds, ArrayType.ArrayBounds)
@@ -212,6 +216,10 @@ class ArrayMixin(metaclass=abc.ABCMeta):
             try:
                 symbol = self.scope.symbol_table.lookup(self.name)
                 datatype = symbol.datatype
+                # Check that the symbol is of ArrayType. (It may be of
+                # UnknownFortranType if the symbol is of e.g. character type.)
+                if not isinstance(datatype, ArrayType):
+                    return False
                 shape = datatype.shape
                 array_bounds = shape[index]
                 if (isinstance(array_bounds, ArrayType.ArrayBounds) and


Test patch:
diff --git a/src/psyclone/tests/psyir/nodes/array_mixin_test.py b/src/psyclone/tests/psyir/nodes/array_mixin_test.py
index 6896a8046..5460dea35 100644
--- a/src/psyclone/tests/psyir/nodes/array_mixin_test.py
+++ b/src/psyclone/tests/psyir/nodes/array_mixin_test.py
@@ -40,7 +40,7 @@
 import pytest
 from psyclone.errors import InternalError
 from psyclone.psyir.nodes import ArrayReference, ArrayOfStructuresReference, \
-    BinaryOperation, Range, Literal, Routine
+    BinaryOperation, Range, Literal, Routine, Assignment
 from psyclone.psyir.symbols import DataSymbol, DeferredType, ArrayType, \
     INTEGER_TYPE
 
@@ -81,13 +81,16 @@ def test_is_upper_lower_bound(fortran_reader):
     code = (
         "subroutine test()\n"
         "real a(10)\n"
+        "character(10) my_str\n"
         "a(1:10) = 0.0\n"
+        "my_str(2:2) = 'b'\n"
         "end subroutine\n")
 
     # Return True as the literal values or the declaration and array
     # reference match.
     psyir = fortran_reader.psyir_from_source(code)
-    array_ref = psyir.children[0].children[0].lhs
+    assigns = psyir.walk(Assignment)
+    array_ref = assigns[0].lhs
     assert array_ref.is_lower_bound(0)
     assert array_ref.is_upper_bound(0)
 
@@ -107,6 +110,11 @@ def test_is_upper_lower_bound(fortran_reader):
     assert not array_ref.is_lower_bound(0)
     assert not array_ref.is_upper_bound(0)
 
+    # Return False if the symbol being referenced is of UnknownFortranType.
+    array_ref = assigns[1].lhs
+    assert not array_ref.is_lower_bound(0)
+    assert not array_ref.is_upper_bound(0)
+
 
 def test_get_effective_shape(fortran_reader, fortran_writer):
     '''Tests for the _get_effective_shape() method.'''