Intrinsic polymorphic assignment is a recent feature of some Fortran compilers (e.g. ifort 18, nagfor 6.2) that is not available in older versions (e.g. ifort 17, gfortran 6.3). A well-known solution that works with these older versions is to use a defined assignment as in the example below (taken and adapted from the book of Chivers and Sleightholme):
module deftypes
type, abstract :: shape_t
integer :: x = 0, y = 0
end type shape_t
type, extends(shape_t) :: circle_t
integer :: radius = 0
end type circle_t
interface assignment(=)
module procedure generic_shape_assign
end interface
contains
subroutine generic_shape_assign ( lhs, rhs )
class(shape_t), intent(in ) :: rhs
class(shape_t), allocatable, intent(out) :: lhs
print*,' --> in generic_shape_assign'
allocate(lhs, source = rhs)
end subroutine generic_shape_assign
end module deftypes
program check_assign
use deftypes
implicit none
class(shape_t), allocatable :: myshape
type (circle_t) :: mycirc1, mycirc2
mycirc1 = circle_t ( 1, 2, 3 )
print*,'A polymorphic assignment: myshape = mycirc1'
myshape = mycirc1
print*,'An intrinsic assignment: mycirc2 = mycirc1'
mycirc2 = mycirc1
end program check_assign
This example, compiles and works well with ifort 15.0.3 and gfortran 6.3.0. But with nagfor 6.2 I get the following error during the compilation (for the line mycirc2=mycirc1
):
Error: check_assign.f90, line 41: Incorrect data type CIRCLE_T (expected SHAPE_T) for argument LHS (no. 1) of GENERIC_SHAPE_ASSIGN
It's not clear to me why this compiler is trying to use the defined assignment in the instruction mycirc2 = mycirc1
while these two variables are not allocatable polymorphic ones.
Of course, if I delete the defined assignment it works with nagfor but not with the other old compilers. Any idea where this error came from and how to get around it?
I believe that the compiler is correct to reject this program. However, if you have a support contract with NAG I strongly advise asking them over taking my comments as definitive.
I will show my reasoning.
It is clear that the reference to the specific procedure generic_shape_assign
like
type(circle_t) mycirc1, mycirc2
call generic_shape_assign(mycirc2, mycirc1)
is not valid. It fails because the actual argument mycirc2
, corresponding to the allocatable polymorphic dummy argument lhs
:
The error message you quote covers rejection of the program for violating this second.
So, that means that generic_shape_assign
is not a valid specific procedure (for this reference) with generic specification assignment(=)
, right? And thus no defined assignment is chosen and the compiler should fall back to intrinsic assignment?
This is where things get murky (at least to me).
I think that the specific subroutine generic_shape_assign
is chosen for the defined assignment and the compiler is therefore correct to reject your program because you aren't calling this specific subroutine correctly.
Let's look further, using Fortran 2008 7.2.1.4 where there's definition of when an assignment statement is a defined assignment statement.
To decide whether the subroutine generic_shape_assign
defines the defined assignment statement mycirc2=mycirc1
we look at the given points:
generic_shape_assign
is a subroutine with two dummy arguments (lhs
and rhs
here);generic_shape_assign
the generic spec assignment(=)
;lhs
(of type shape_t
) is type compatible with mycirc2
(of dynamic type circle_t
); rhs
similarly;We meet all of the requirements for this being a defined assignment: there is no requirement which states that defined assignment requires the chosen subroutine to be callable!
In summary:
It's not clear to me why this compiler is trying to use the defined assignment in the instruction
mycirc2 = mycirc1
while these two variables are not allocatable polymorphic ones.
Because whether defined assignment is used is unrelated to whether the left- and right-hand sides are polymorphic or allocatable.
Finally, I think the diagnostic message from the compiler could be improved whether my reasoning is correct or incorrect.