j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
175 stars 14 forks source link

Usable polymorphism in coarrays #251

Open everythingfunctional opened 2 years ago

everythingfunctional commented 2 years ago

Currently there are constraints preventing the use of polymorphism in coarrays. Specifically

C917 (R911) Except as an actual argument to an intrinsic inquiry function or as the designator in a type parameter inquiry, a data-ref shall not be a coindexed object that has a polymorphic allocatable potential subobject component.

and

C918 Except as an actual argument to an intrinsic inquiry function or as the designator in a type parameter inquiry, if the rightmost part-ref is polymorphic, no other part-ref shall be coindexed.

I suspect that it would be possible to rewrite these constraints in such a way to allow reference to a polymorphic entity on another image without allowing one image to perform an allocation on another. My proposed rewriting would be

C917 If data-ref is a coindexed object that has a polymorphic allocatable potential subobject component it shall not appear in a variable definition context

and

C918 If the rightmost part-ref is polymorphic and any other part-ref is coindexed, the data-ref shall not appear in a variable definition context.

I'm not sure if I've got the wording quite right, but I think this is doable.

klausler commented 2 years ago

These new versions of the constraints would be easy to check, and I haven't been able to come up with a failure mode that they might enable. SGTM.

everythingfunctional commented 2 years ago

I've come up with an example program that violates the current constraints, but does not violate my proposed new constraints.

program
implicit none

type, abstract :: parent
end type

type, extends(parent) :: child
   character(len=:), allocatable :: message
end type

type :: wrapper
  class(parent), allocatable :: item
end type

type(wrapper) :: coarray[*]

if (this_image() == 1) then
  coarray%item = child("Hello, World!")
end if
sync all
if (this_image() /= 1) then
  coarray%item = coarray[1]%item
end
select type (the_item => coarray%item)
type is (child)
  print *, the_item%message
end select
klausler commented 2 years ago

I concur that this example violates the named constraints in a way that makes them seem surprising.

However, there is a possible implementation motivation for those constraints that has occurred to me: a polymorphic component that is not deallocated/disassociated will need some means to identify its dynamic type, and that's typically implemented by means of a pointer to some kind of compiler-created type description record (which also holds the information necessary for I/O, overrideable TBP bindings, finalization, &c.). A type description record pointer from one image would have to be usable (or identical) to its analog on the local image in order to serve as the RHS of an allocating LHS (as above), to work with SELECT TYPE and SAME_TYPE_AS, and handle I/O. This is an implementation requirement that comes for free in some coarray implementation models -- MPI ranks all running the same executable, for example -- but might require pointer mapping or be simply impossible in some other coarray implementation models.

So I encourage you to bring the possible relaxation of these constraints up for discussion, but be advised, it may not be the no-brainer that we (or at least I) though it would be.

FortranFan commented 2 years ago

@everythingfunctional wrote May 17, 2022 4:01 PM EDT:

I've come up with an example program that violates the current constraints

What do the current compiler implementations detect and report with this program?

Here I mean besides the first line itself where program-name is missing, or line 19 with the typo where end if was intended, and so forth.

everythingfunctional commented 2 years ago

coarray[1]%item violates C918. I'll fix the example and report the messages issued by the various compilers I have access to.

everythingfunctional commented 1 year ago

With the "fixed" example program as follows, I get error messages from compilers like

program main
    implicit none

    type, abstract :: parent
    end type

    type, extends(parent) :: child
       character(len=:), allocatable :: message
    end type

    type :: wrapper
      class(parent), allocatable :: item
    end type

    type(wrapper) :: coarray[*]

    if (this_image() == 1) then
      coarray%item = child("Hello, World!")
    end if
    sync all
    if (this_image() /= 1) then
      coarray%item = coarray[1]%item
    end if
    select type (the_item => coarray%item)
    type is (child)
      print *, the_item%message
    end select
end program
$ gfortran -fcoarray=single main.f90
main.f90:22:21:

   22 |       coarray%item = coarray[1]%item
      |                     1
Error: Polymorphic subobject of coindexed object at (1)
$ ifort -coarray=single main.f90 
main.f90(22): catastrophic error: **Internal compiler error: internal abort** Please report this error along with the circumstances in which it occurred in a Software Problem Report.  Note: File and line given may not be explicit cause of this error.
compilation aborted for main.f90 (code 1)
$ nagfor -coarray main.f90
NAG Fortran Compiler Release 7.1(Hanzomon) Build 7108
[NAG Fortran Compiler normal termination]
$ ./a.out 
 Hello, World!
 Hello, World!
 Hello, World!
 Hello, World!
 Hello, World!
 Hello, World!
 Hello, World!
 Hello, World!

So at least one compiler already allows this apparently.

nncarlson commented 1 year ago

So at least one compiler already allows this apparently.

But not for long if Malcolm catches wind of it :smile:

klausler commented 1 year ago

NAG's coarrays are only for an SMP with a single address space, right? So the implementation concern that drove the constraint for coarrays when images don't share one code address space doesn't really apply.

nncarlson commented 1 year ago

NAG's coarrays are only for an SMP with a single address space, right?

This is getting beyond my understanding, but each image is a separate process in its own address space, using shared memory transport for coarray communication, but restricted to running on a single SMP machine/OS/kernel.

klausler commented 1 year ago

NAG's coarrays are only for an SMP with a single address space, right?

This is getting beyond my understanding, but each image is a separate process in its own address space, using shared memory transport for coarray communication, but restricted to running on a single SMP machine/OS/kernel.

Yes, that's a more clear way to put it. The point is that addresses of code and read-only static data are valid in any/every image.

everythingfunctional commented 1 year ago

I found an additional aspect that may need to change as well for this to really do what you'd expect. In Section 15.5.1, there is Constraint

C1528 (R1522) A data-ref shall not be a polymorphic subobject of a coindexed object.

and to go with it, Note 1 says

When resolving type-bound procedure references, constraints on the use of coindexed objects ensure that the coindexed object (on the remote image) has the same dynamic type as the corresponding object on the local image. Thus a processor can resolve the type-bound procedure using the coarray variable on its own image and pass the coindexed object as the actual argument

If the changes I proposed are made, I believe it may be possible to simply delete these, but there may be some other text that would need to be added.