fparser icon indicating copy to clipboard operation
fparser copied to clipboard

Inconsistent matching of inline calls and derived type member references

Open reuterbal opened this issue 2 years ago • 7 comments

Yet another edge case, which is most likely not possible to resolve without having procedures in the symbol table. However, I felt it might be useful to document it:

Function calls in expressions and derived type member references are represented inconsistently. One distinction seems to be made based on whether named arguments are used or not. A little example:

fcode = """
module inline_call_mod
    implicit none

    type mytype
        integer :: val
        integer :: arr(3)
    contains
        procedure :: some_func
    end type mytype

contains

    function check(val, thr) result(is_bad)
        integer, intent(in) :: val
        integer, intent(in), optional :: thr
        integer :: eff_thr
        logical :: is_bad
        if (present(thr)) then
            eff_thr = thr
        else
            eff_thr = 10
        end if
        is_bad = val > thr
    end function check

    function some_func(this) result(is_bad)
        class(mytype), intent(in) :: this
        logical :: is_bad

        is_bad = check(this%val, thr=10) &
            &   .or. check(this%arr(1)) .or. check(val=this%arr(2)) .or. check(this%arr(3))
    end function some_func
end module inline_call_mod
""".strip()

from fparser.common.readfortran import FortranStringReader
from fparser.two.parser import ParserFactory
reader = FortranStringReader(fcode)
parser = ParserFactory().create(std='f2003')
ast = parser(reader)
ast

The four calls to check in the is_bad = ... expression are represented as:

  • check(this%val, thr=10):
Structure_Constructor(Type_Name('check'), Component_Spec_List(',', (Proc_Component_Ref(Name('this'), '%', Name('val')), Component_Spec(Name('thr'), Int_Literal_Constant('10', None))))
  • check(this%arr(1)):
Part_Ref(Name('check'), Section_Subscript_List(',', (Data_Ref('%', (Name('this'), Part_Ref(Name('arr'), Section_Subscript_List(',', (Int_Literal_Constant('1', None),))))),)))
  • check(val=this%arr(2)):
Structure_Constructor(Type_Name('check'), Component_Spec_List(',', (Component_Spec(Name('val'), Data_Ref('%', (Name('this'), Part_Ref(Name('arr'), Section_Subscript_List(',', (Int_Literal_Constant('2', None),)))))),)))
  • check(this%arr(3)):
Part_Ref(Name('check'), Section_Subscript_List(',', (Data_Ref('%', (Name('this'), Part_Ref(Name('arr'), Section_Subscript_List(',', (Int_Literal_Constant('3', None),))))),)))

What should, to my understanding, be a Function_Reference, is either represented as Structure_Constructor (named argument present) or Part_Ref (no named argument present). Additionally, the reference to this%val is represented as a Proc_Component_Ref in the first case, but (correctly?) identified as a Data_Ref in all others.

reuterbal avatar Jan 11 '23 22:01 reuterbal

To add a further example to this, Daley has found that this behaviour (of matching a Structure_Constructor can be triggered by simply having a real, literal as argument to a function. If that argument is instead an integer literal then a Part_Ref results.

arporter avatar Oct 19 '23 08:10 arporter

Fundamentally, until we can resolve the type of e.g. check in @reuterbal's example then we have no way of know whether such an access is a Part_Ref, Structure_Constructor or Function_Reference.

arporter avatar Oct 19 '23 08:10 arporter

In the following code:

      thread_count = OMP_GET_NUM_THREADS()
      thread_id = OMP_GET_THREAD_NUM()

both of the OMP calls are parsed as Structure_Constructor. Can a structure constructor have no arguments?

arporter avatar Jul 15 '24 14:07 arporter

I think that's allowed as long as all derived type components are allocatable or have default initialisers. https://j3-fortran.org/doc/year/10/10-007.pdf#page=98

reuterbal avatar Jul 15 '24 14:07 reuterbal

Couldn't we simply avoid matching Structure_Constructors? We would still be wrong (as not returning what the standard says it is - now we do the same just the other way around) but the tools that use fparser would have them as Function Calls, which is a reasonable approximation as they behave like them, and we won't be missing actual functions.

sergisiso avatar Jul 15 '24 15:07 sergisiso

I created #449 to test this. Note that this does not attempt to solve the conflict with PartRef also mentioned in the original comment, only the Structure_Constructor.

sergisiso avatar Jul 15 '24 16:07 sergisiso