Type bound generic assignment not being inherited

Type bound generic assignment not being inherited

Consider the following skeletal code:

 module abstract_m
private
public:: abs_t
type ,abstract :: abs_t
contains
!other bindings
procedure(sub_abs_t_abs_t) ,deferred :: assign
generic :: assignment(=) => assign
end type
abstract interface
elemental subroutine assign(lhs,rhs)
import :: abs_t
class(abs_t) ,intent(inout) :: lhs
class(abs_t) ,intent(in) :: rhs
end subroutine
end interface
end module
module concrete_m
use abstract_m ,only:abs_t
implicit none
private
public :: cncrt_t
type ,extends(abs_t) :: cncrt_t
private
!State/data variables
contains
procedure :: assign => copy
procedure :: some_op
end type
contains
elemental subroutine copy(lhs,rhs)
class(cncrt_t) ,intent(inout) :: lhs
class(abs_t) ,intent(in) :: rhs
select type(rhs)
class is(cncrt_t) lhs%.... = rhs%.... etc.
:
end select type
end subroutine
elemental function some_op(lhs,rhs) result(res)
class(cncrt_t) ,intent(in) :: lhs
class(abs_t) ,intent(in) :: rhs
class(abs_t) ,allocatable :: res
allocate(res,source=lhs)
select type(rhs)
class is (cncrt_t)
!Shouldn't this call the generic assignment bound to Assign in the abstract class, implemented as copy?
res = lhs .other_op. rhs
:
end select type
end function
end module 

When I run the syntax checker on a similar code I get the following error message:

 $ ifort -warn -stand f03 -syntax-only -fpp statN.F90 statN.F90(97):
error #8304: In an intrinsic assignment statement, variable shall not be polymorphic. [LOCAL_RES]
local_res = rhs !I think this will call copy...nope.jpg
-------------^ 

I believe that the generic assignment specified in the abstract type should be inherited by the implementation. Therefore, a polymorphic object of class(abs_t) or one of it's children should try to call assign() when it encounters an assignment statement like local_res = .... Please correct me if my understanding is flawed or I missed some subtlety surrounding polymorphism, inheritance and generic type bound procedures.

I'm super swamped at the moment, and don't really have time to go through the original code and make a simplified reproducer. For the time being I can work around this by calling the copy subroutine directly rather than through the generic type bound assignment. I will try to work up a reproducer soon.

-Zaak
9 posts / 0 nouveau(x)
Dernière contribution
Reportez-vous à notre Notice d'optimisation pour plus d'informations sur les choix et l'optimisation des performances dans les produits logiciels Intel.

In my haste I forgot to mention that this is with: ifort (IFORT) 13.0.2 20130314 on a 64 bit Intel Mac OS X (Mavericks). I don't know if the issue was corrected in ifort 14.x as I haven't had a chance to upgrade my home machine (and work/school hasn't upgraded yet either)

-Zaak

OK, no one is responding, but it seems that this code is affected by another issue, and is not standards conforming. I'm going to fix the problems surrounding deallocation of polymorphic entities in pure subroutines and then I'll test this again. Hopefully that fix will resolve this issue. I'll report back later today or tomorrow--lots to do today!

-Zaak

Hello Zaak,

since I had similar issues (on ifort 14.0.1), maybe I should bring up those problems here too. The problem occurs only with assignment but not with other binary operators in my code; and only for abstract types, as you already mentioned.

I think the core of the problem is that having an abstract parent is the only setup where ifort must do dynamic generic resolution on type-bound assignment operators depending on the dynamic type; and only calling directly from the lhs via %copy or from an abstract lhs explicitly enforces that. Instead, I have a feeling that ifort is trying to resovle the generic assignment staticall (which fails).

Here's a sample which is essentially your initial sample-code, but shows the same issue on ifort 14.0.1:

module m
    implicit none
 
    ! extendable abstract type
 
    type, abstract :: parent_type
    contains
        ! some generic type-bound operator
        procedure(copy_interf), deferred :: copy
        generic :: assignment(=) => copy
    end type
 
    abstract interface
        subroutine copy_interf(lhs,rhs)
            import parent_type
            class(parent_type), intent(inout) :: lhs
            class(parent_type), intent(in) :: rhs
        end subroutine
    end interface
 
    type, extends(parent_type) :: child_type
    contains
        procedure :: copy => copy_child
    end type
contains
    subroutine copy_child(lhs,rhs)
        class(child_type), intent(inout) :: lhs
        class(parent_type), intent(in) :: rhs
    end subroutine
end module 
 
program p
    use m
    implicit none
 
    type(child_type) :: static_child
    class(child_type),  allocatable :: child_declared_child
    class(parent_type), allocatable :: child_declared_parent
 
    allocate(child_type :: child_declared_child)
    allocate(child_type :: child_declared_parent)
 
    static_child         = static_child
    child_declared_child     = static_child
    child_declared_parent     = static_child ! ERROR
 
    static_child         = child_declared_child
    child_declared_child     = child_declared_child
    child_declared_parent     = child_declared_child ! ERROR
 
    static_child         = child_declared_parent
    child_declared_child     = child_declared_parent
    child_declared_parent     = child_declared_parent
end program

Each line with '! ERROR' comment triggers the following error messages:

error #6197: An assignment of different structure types is invalid.   [STATIC_CHILD]
    child_declared_parent     = static_child ! ERROR
----------------------------------^
error #8304: In an intrinsic assignment statement, variable shall not be polymorphic.   [CHILD_DECLARED_PARENT]
    child_declared_parent     = static_child ! ERROR
--------^

With regards
Ferdinand

...and while we are already at this, here's an ifort 14.0.1 internal compiler error if one makes the assignment from above non-virtual:

module m
    implicit none
 
    ! extendable derived type
    type :: parent_type
    end type
 
    type, extends(parent_type) :: child_type
    contains
        procedure :: copy
        generic :: assignment(=) => copy
    end type
contains
    subroutine copy(lhs,rhs)
        class(child_type), intent(inout) :: lhs
        class(parent_type), intent(in) :: rhs
    end subroutine
end module 
 
program p
    use m
    implicit none
 
    type(child_type) :: static_child
    class(parent_type), allocatable :: child_declared_parent
 
    allocate(child_type :: child_declared_parent)
 
    ! try type-bound assignment
    call static_child%copy(child_declared_parent)    ! OK
    static_child = child_declared_parent       ! ICE (catastrophic error)
end program

Regards
Ferdinand

Thank you for the convenient reproducers. I reported both issues to Development and will update this forum thread as I hear back from them.

(Internal tracking id: DPD200249796 - Type bound generic assignment not inherited for abstract types)
(Internal tracking id: DPD200249798 - Internal compiler error related to non-virtual type-bound assignment)

(Resolution Update on 02/14/2014): The defect DPD200249798 is fixed in the Intel® Fortran Composer XE 2013 SP1 Update 2 release (Version 14.0.2.144 Build 20140120 - Linux)

Development has a fix for the internal error (DPD200249798) that I expect to be targeted to the next Composer XE 2013 SP1 update early next year. The error occurs when using a type-bound assignment when either there are no fields in the type of interest or the variable is class(*).

In addition to the work around you noted, Development noted another is to add a dummy field to the type declaration for parent_type.

I will update the posting again when the fix is available.

Kevin,

Thanks for the work around. That is a much more attractive alternative.

-Zaak

I confirmed the fix to the internal error (DPD200249798) in the latest Composer XE 2013 SP1 Update 2 release now available from the Intel Registration Center.

There is no new update on the type bound generic assignment (DPD200249796) issue. I will update once I hear anything.

Laisser un commentaire

Veuillez ouvrir une session pour ajouter un commentaire. Pas encore membre ? Rejoignez-nous dès aujourd’hui