Version 1.2 of ai22s/ai22-0024-1.txt
!standard 3.9.3(7/5) 22-01-20 AI22-0024-1/01
!standard 4.1.3(9.2/3)
!class binding interpretation 22-01-20
!status work item 22-01-20
!status received 21-04-28
!priority Low
!difficulty Easy
!qualifier Clarification
!subject Abstract prefixed views
!summary
** TBD **
!question
Following is a distillation of another ACATS test that gets different results
in different Ada 2012 compilers:
procedure B950001 is
package Nested is
type Intf is synchronized interface;
procedure PEN1 (Param : in out Intf) is abstract
with Synchronization => By_Entry;
end Nested;
generic
with procedure P;
package Gen1 is
Decl : Natural;
end Gen1;
procedure Test (Intf_In_Parm : in Nested.Intf'Class;
Intf_In_Out_Parm : in out Nested.Intf'Class) is
package GPE139 is new Gen1 (Intf_In_Parm.PEN1); --
package GPE149 is new Gen1 (Intf_In_Out_Parm.PEN1); --
begin
null;
end Test;
...
The test is trying to check legality of prefixes of prefixed views.
However, one of the tested compilers rejected the "OK" instantiation because
the subprogram is abstract.
The actual here is a prefixed view of an abstract subprogram, but this view is
of a dispatching call that is legal for an actual call. But is it legal as the
actual of a generic subprogram? Should it be?
The test also renames these calls:
procedure RPE139 renames Intf_In_Parm.PEN1; -- ERROR: Prefix is constant
procedure RPE149 renames Intf_In_Out_Parm.PEN1; -- OK. Prefix is variable
Would a call on RPE149 be legal? If the prefixed view is abstract, it would be
odd if a call on the renames is legal (the dispatching is bound in the prefix).
!recommendation
** TBD. **
!wording
** TBD **
!discussion
4.1.3(9.2/3) defines a prefixed view to be a view of a subprogram; is not
itself a call; it is a subprogram that is called in the usual way (with one
less parameter).
6.4(9.1/5) makes it clear that a call on a prefixed view is equivalent to the
underlying usual call. So a dispatching call on a prefixed view should be
allowed.
However, there don't appear to be any description of the properties of the
prefixed view itself. This matters when the prefixed view is renamed or used
as the actual for a generic formal subprogram. In particular, is the renamed
prefixed view still abstract even if the prefixed view represents part of a
dispatching call? We need to answer this.
----
We need to break down this problem into a number of cases:
In the case where there the first parameter of the underlying abstract
subprogram is the only controlling parameter, then there are two cases:
* if the type of the prefix is class-wide, a call would be a legal
dispatching call and the other parameters (if any) have no effect
on that. So in this case, we should allow the prefixed view to be
created, and it should not be abstract;
* otherwise (the type of the prefix is not class-wide), a call would be
an illegal call on an abstract operation, and again the other parameters
have no effect on that. So in that case, the prefixed view should be
illegal.
[Note: In this latter case, we want to make the prefixed view illegal to
follow the language design principle that if a declaration creates an item
for which any use (in this case, call) would be illegal, then the declaration
itself should be illegal.]
In the case where the first parameter of the underlying abstract subprogram
is not a controlling parameter, then one or more of the remaining parameters
has to be the controlling parameter(s). In such a case, the legality of the
call depends on actual values for those other parameters -- the prefixed view
should still act as if it is abstract. Ergo, we allow the prefixed view, and
it still is abstract.
Finally, in other cases, we have more than one controlling parameter with
one of them being the first. Creating a prefixed view of such a subprogram
would cause a rather weird "partially dispatching" subprogram, where both
explicit and implicit parameters are controlling the dispatching. Depending
on how that was interpreted, one could have a mixed statically and
dynamically bound call, a tag check not obvious in the code, or an illegal
call. In any case, one would need additional "strings" (either statically
or dynamically) in order to match the semantics of either the fully
expanded call or the profile of the prefixed view (and it would not be
possible to match the semantics of both exactly, as it is with other calls).
It might help to look at an example:
package P1 is
type Intf is interface;
function F1 (A : in Intf; B : in Natural) return Boolean is abstract;
function F2 (A : in Natural; B : in Intf) return Boolean is abstract;
function F3 (A, B : in Intf) return Boolean is abstract;
end P1;
procedure Test (Obj : in P1.Intf'Class; Val : in Natural) is
function R1 (B : in Natural) return Boolean renames Obj.F1; --
function R2 (B : in P1.Intf) return Boolean renames Val.F2; --
function R3 (B : in P1.Intf) return Boolean renames Obj.F3; --
begin
if R1(1) then --
null;
elsif R2(Obj) then --
null;
elsif R3(A) then --
null;
end if;
end Test;
R1 and R2 demonstrate the first two cases above. R1 is treated as not being
abstract - the dispatching is "hidden" in the prefixed view.
On the other hand, R2 is still an abstract routine that needs a class-wide
actual parameter in order to be a dispatching call. (??? - note that it
isn't primitive. What happens for a rename of an abstract routine with a
controlling parameter in a place that is not primitive?)
Finally, R3 demonstrates the last case. Note that the profile of R3 has only
a single controlling parameter; moreover, by language rules it isn't even
primitive. Regardless of what semantics are chosen for R3, it cannot have
the same semantics as both the given profile and the the fully expanded
call.
Note that the oddities don't require the underlying subprogram to be abstract.
We think the best solution is the make such bizarre prefixed views illegal.
!ACATS test
The existing B950001 contains these cases (now commented out).
!appendix
From: Randy Brukardt
WG 9 Review issue #175 - May 22, 2021
Following is a distillation of another ACATS test that gets different results
in different Ada 2012 compilers:
procedure B950001 is
package Nested is
type Intf is synchronized interface;
procedure PEN1 (Param : in out Intf) is abstract
with Synchronization => By_Entry;
end Nested;
generic
with procedure P;
package Gen1 is
Decl : Natural;
end Gen1;
procedure Test (Intf_In_Parm : in Nested.Intf'Class;
Intf_In_Out_Parm : in out Nested.Intf'Class) is
package GPE139 is new Gen1 (Intf_In_Parm.PEN1); -- ERROR: Prefix is constant
package GPE149 is new Gen1 (Intf_In_Out_Parm.PEN1); -- OK. Prefix is variable
begin
null;
end Test;
...
The test is trying to check legality of prefixes of prefixed views.
However, one of the tested compilers rejected the "OK" instantiation because
the subprogram is abstract.
The actual here is a prefixed view of an abstract subprogram, but this view is
of a dispatching call that is legal for an actual call. But is it legal as the
actual of a generic subprogram? Should it be?
I can't find anything definitive. 3.9.3(7/5) suggests that the subprogram that
is called is abstract, but whether that is still the case for a generic actual
is unclear.
It seems weird at best that you can call the subprogram but that you couldn't
pass it as a generic actual. Could there be a reason for that??
I'd expect a similar issue with an instance without the synchronization, but I
have not tested (or analyzed) that case.
The test also renames these calls:
procedure RPE139 renames Intf_In_Parm.PEN1; -- ERROR: Prefix is constant
procedure RPE149 renames Intf_In_Out_Parm.PEN1; -- OK. Prefix is variable
Would a call on RPE149 be legal? If the prefixed view is abstract, it would be
odd if a call on the renames is legal (the dispatching is bound in the prefix).
Tucker Taft suggested that a potential precedent might be the rules for what
happens when you instantiate a generic having a formal extension parameter
with a class-wide type. Effectively wrappers are created for each of the
primitives, which take 'Class parameters and do the dispatching-related checks
and the actual dispatching call internally. We should think of a prefixed-view
of a subprogram that has a class-wide prefix as effectively a non-abstract
wrapper, in analogy with the rules given in 12.5.1(23.1-23.3). Thus the lines
marked as "OK" are in fact "OK."
Note that the operation should still be abstract if the call isn't dispatching
(that is, the prefix is not the controlling parameter of the call).
This one needs quite a bit of wording and thought (it's not at all simple), so
it is best deferred.
****************************************************************
Questions? Ask the ACAA Technical Agent