Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Generic Interface Ambiguity

Thomas_F_1
Beginner
957 Views

The following code sample with generic assignment(=) interfaces compiles fine under Version 15.0.5.280. I just installed Version 16 and it produces an error.

module test
implicit none
private

    type, public :: ref_t
        private
        integer :: idum = 0
    contains
        generic :: assignment(=) => get_new
        generic :: assignment(=) => acquire
        procedure, private :: get_new
        procedure, private :: acquire
    end type

contains

    subroutine get_new(my,ptr)
        class(ref_t), intent(out) :: my
        class(*), pointer, intent(in) :: ptr
        print *, "get_new"
        my%idum = 1
    end subroutine

    subroutine acquire(my,ref)
        class(ref_t), intent(out) :: my
        class(ref_t), intent(in)  :: ref
        print *, "acquire"
        my%idum = ref%idum+1
    end subroutine

end module

program main
call run
contains
subroutine run
use test

    type(ref_t) a,b
    class(*), pointer :: p

    a = p
    b = a

end subroutine
end program

With Version 15, I can compile and get the following output:

$ ./GenericAmbiguity.exe
 get_new
 acquire

But with Version 16, I get the following error message:

$ ifort GenericAmbiguity.f90
Intel(R) Visual Fortran Compiler for applications running on IA-32, Version 16.0 Build 20151021
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

GenericAmbiguity.f90(24): error #8437: The type/rank signature for the arguments of this specific subroutine matches another specific subroutine that shares the same ASSIGNMENT generic binding.   [ACQUIRE]
        subroutine acquire(my,ref)
-------------------^
compilation aborted for GenericAmbiguity.f90 (code 1)

Since `acquire` has a more specific interface than `get_new`, it seems that there should be no ambiguity (unless, of course, the actual argument is of type `class(ref_t),pointer`).

So why the change from V15 to V16?

 

0 Kudos
4 Replies
Steven_L_Intel1
Employee
958 Views

since class(*) matches anything, it is ambiguous when the second argument is compatible with class(ref_t). The older compiler did not catch the error. Note that one argument being a pointer and the other not is not a distinguishing characteristic, since one can pass a non-pointer to the pointer and the compiler will "fake" a pointer, as the language specifies.

I'll note that a future version of the compiler gives a somewhat more helpful message:

U607413.f90(24): error #5286: Ambiguous generic interface ASSIGNMENT(=): previously declared specific procedure GET_NEW is not distinguishable from this declaration. [ACQUIRE]
    subroutine acquire(my,ref)
---------------^

0 Kudos
Thomas_F_1
Beginner
957 Views

I think I understand the problem. But by analogy, I would expect the code below to have the same problem, but it doesn't. Since a_sub can always match the arguments to b_sub, there should be an ambiguity, but there isn't. Is "class(*)" so super-special that a routine with a more specific argument can't be distinguished?

To turn the question around, how would one define a generic interface so that one routine could respond for one type (i.e. class(ref_t)), but a different routine would be called for all other types (i.e. class(*))?

Thanks much!

module m

	type :: a
	
	end type
	
	type, extends(a) :: b
	
	end type
	
contains

	subroutine a_sub(a1,a2)
		class(a) :: a1
		class(a) :: a2
	end subroutine

	subroutine b_sub(b1,b2)
		class(b) :: b1
		class(b) :: b2
	end subroutine

end module

 

0 Kudos
Steven_L_Intel1
Employee
957 Views

You haven't declared a generic in this example. If you add one, like this:

	interface mygen
	   module procedure a_sub
	   module procedure b_sub
	end interface

You get:

t.f90(23): warning #6738: The type/rank/keyword signature for this specific procedure matches another specific procedure that shares the same generic-name.   [B_SUB]
        subroutine b_sub(b1,b2)
-------------------^

class(*) matches any type. For generic resolution, some other argument must also be distinguishable. So to answer your question, no, that's not possible. The way to do what you want is a single routine that accepts a class(*) argument and then does a SELECT TYPE to determine what it's going to do with it.

0 Kudos
Thomas_F_1
Beginner
957 Views

 

You haven't declared a generic in this example

Oops. Sorry 'bout that. I've just installed V16 and am getting a boatload of ICEs as well as this error. So far this is the only one I've been able to narrow down to a simple example and I missed that part. I thought about using SELECT TYPE, but that doesn't enforce the pointer requirement that I'd like to have, but I have some other ideas that I can pursue.

Thanks for the clarification.

Regarding the ICEs, I'll make a formal submission if I can narrow it down a bit. 

0 Kudos
Reply