Question about interface matching

Could someone please tell me whether the following code is standards conformant, and if so why? I contend that both the declared and dynamic type of bar do not match the interface and thus the code should not compile or execute without error. But gfortran, intel, and nag all compile and execute this code without complaint. Is there something about interface matching and argument types that I’m not understanding?

module foo_m
   implicit none

   type :: foo_t
       procedure :: copy_into
   end type

   type, extends(foo_t) :: bar_t
   end type
   subroutine copy_into(self, rhs)
       class(foo_t), intent(inout) :: self
       type(foo_t), intent(inout) :: rhs
   end subroutine
end module

program main
   use foo_m, only: foo_t, bar_t

   implicit none

   type(foo_t) :: foo
   class(foo_t), allocatable :: bar

   bar = bar_t()
   call foo%copy_into(bar)
end program

A really interesting question that I don’t think I’d ever considered before. @pmk is correct. If you’re looking for places in the standard (F18), p2 (key is “type compatible”) and p3 (“associated with the declared type part of that actual argument”) seem to speak to your question.

Very interesting, but I have to agree with Brad that it is counterintuitive. What’s the point of having “class” if an argument declared as “type” works for children too (here, that is, I bet elsewhere it does not)? Is “class” only necessary for the “self” argument in a method?

Confusing as it may be, the standard, starting with the Fortran 2003 revision where support toward polymorphic types was introduced, has maintained in the section on CLASS where it explains what is type compatible:

“A nonpolymorphic entity is type compatible only with entities of the same declared type”.

The section on argument association of actual with dummy argument then refers to that section.

In the code in the original post, as explained upthread, the declared type of object bar matches that of the dummy argument and thus the code conforms.

Were the declaration to be class(bar_t), allocatable :: bar instead for example, the code will not conform.

1 Like

Thank you all for the explanations and references to the standard. I’m not sure I understand why the standard is written to allow this, but at least now I’m aware of it.