AI22-0021-1
!standard 4.3.5(7/5) 22-09-06 AI22-0021-1/04
!standard 4.3.5(8/5)
!standard 4.3.5(9/5)
!standard 4.3.5(11/5)
!class binding interpretation 22-01-17
!status Amendment 1-2022 22-02-03
!status WG9 Approved 22-10-18
!status ARG Approved 16-0-0 22-02-03
!status work item 22-01-17
!status received 21-11-09
!submitter Randy Brukardt
!priority Low
!difficulty Easy
!qualifier Clarification
!subject Aggregate aspect resolution should not be too smart
The requirements on the classification of the types of the profile of subprograms used in an Aggregate aspect should be handled by Legality Rules and not resolution.
The parameters of subprograms specified in an Aggregate aspect should not be explicitly aliased. Neither the element type nor the key type of a container aggregate should be an anonymous access type.
(1) 4.3.5(7-9/5) requires the element type to be nonlimited. Additionally, 4.3.5(8/5) requires key type to be discrete while 4.3.5(9/5) requires the key type to be nonlimited. These are resolution rules; we typically do not use "nonlimited" in resolution (Ada 95 did, but that was removed, even in places where we did not have to do that), and probably not "discrete" in most cases. Should those requirements be Legality Rules instead? (Yes.)
(2) 4.3.5(6-9/5) allows the specified subprograms to have aliased parameters. Particularly for functions that return a composite object, such parameters drag in accessibility checks which could make some calls illegal. We felt it necessary to ban such parameters for Integer_Literal and similar aspects (see, for instance, 4.2.1(3/5)), and this is a similar case. Should we do that here? (Yes.)
(3) 4.3.5(7-9/5) allows the element type and (for Add_Named only) the key type to be an anonymous access type. Anonymous access parameters involve dynamic accessibility, and would require us to specify the accessibility of any temporaries used for the evaluation of a container aggregate. That seems to be an unnecessary complication, should these also be banned? (Yes.)
(See Summary.)
Modify 4.3.5(7/5):
The procedure_name specified for Add_Unnamed for an Aggregate aspect shall denote exactly one procedure that has two parameters, the first an in out parameter of the container type, and the second an in parameter [of some nonlimited type,]{whose type is} called the element type of the container type.
Modify 4.3.5(8/5):
The function_name specified for New_Indexed for an Aggregate aspect shall denote exactly one function with a result type of the container type, and two parameters of the same [discrete ]type, [with that type being]{called} the key type of the container type.
Modify 4.3.5(9/5):
The procedure_name specified for Add_Named or Assign_Indexed for an Aggregate aspect shall denote exactly one procedure that has three parameters, the first an in out parameter of the container type, the second an in parameter [of a nonlimited ]{whose type is called} [(]the key type of the container type[)], and the third, an in parameter [of a nonlimited type that]{whose type} is called the element type of the container type.
Modify 4.3.5(11/5):
For an Aggregate aspect, {neither the element type nor the key type (if any) of the container type shall be a limited type. Additionally, }the key type of Assign_Indexed shall be the same type as that of the parameters of New_Indexed{, and that type shall be a discrete type}. [Additionally, if]{If} both Add_Unnamed and Assign_Indexed are specified, the final parameters shall be of the same type -- the element type of the container type.
{None of the subprograms specified for an Aggregate aspect shall have a formal access parameter, nor an explicitly aliased formal parameter.}
{AARM Reason: Both access parameters and explicitly aliased parameters add additional requirements on the corresponding actual parameter. These complicate the description and implementation of container aggregates with little benefit. Thus we make them illegal. This means neither the element type nor the key type (if any) of the container type can be an anonymous access type.}
(1) In Ada 2005, we removed the cases where resolution depended on whether a type was limited or not. This was done to support build-in-place, but for consistency, it was done throughout the language. For instance, assignment statements still require a nonlimited type, but this is enforced with a Legality Rule, rather than resolution, in Ada 2005 and later.
Note that resolving to nonlimited could become a compatibility problem, as it is easy to imagine a future version of container aggregates that allowed newly constructed limited components. If we use "nonlimited" in the resolution rules, then such a change would be subtly incompatible, as it is possible that some existing (and unchanged) aspects would no longer resolve. If "nonlimited" only appears in Legality Rules, then a change is a pure extension (as we would just be removing/weakening a Legality Rule). The sooner we make this change, the less incompatible it will be (simply because there will be less code to be affected).
Besides the inconsistency with Ada 2005, it is also the case that the two routines used for indexed aggregates resolve differently: New_Indexed resolves its key parameters to be a discrete type, while Assign_Indexed only resolves its key parameter to be a nonlimited type. So one can imagine overloading that would resolve for one but not the other.
Finally, we generally don't want resolution to be "too smart". While compilers can implement any resolution that we can dream up, we want the rules to be understandable to human programmers in every circumstance.
(2) In addition to accessibility checks on functions, there are also additional restrictions on the subtypes of an actual parameter to an explicitly aliased parameter (in order that 'Access can be safely taken of a part of such a parameter). These would at best clutter up the dynamic equivalence, and at worst would make some aggregates illegal. In the interest of avoiding creeping complexity, we don't allow aliased parameters here.
(3) If we allowed any of the parameters of the various subprograms to be anonymous access, we would need to put restrictions on the accessibility of the items passed to the various calls to the routines, in order that a programmer could depend upon a "reasonable" implementation. The use of anonymous access in this way does not seem to be an important use of container aggregates, and as such we choose to make them illegal rather than making the rules more complex for an unlikely usage.
@drepl
The @i{procedure_}@fa{name} specified for Add_Unnamed for an Aggregate
aspect shall denote exactly one procedure that has two parameters, the first
an @b{in out} parameter of the container type, and the second an @b{in}
parameter of some nonlimited type, called the @i{element type} of the
container type.
@dby
The @i{procedure_}@fa{name} specified for Add_Unnamed for an Aggregate
aspect shall denote exactly one procedure that has two parameters, the first
an @b{in out} parameter of the container type, and the second an @b{in}
parameter whose type is called the @i{element type} of the container type.
@drepl
The @i{function_}@fa{name} specified for New_Indexed for an
Aggregate aspect shall denote exactly one function with a result type of the
container type, and two parameters of the
same discrete type, with that type being the @i{key type} of the container type.
@dby
The @i{function_}@fa{name} specified for New_Indexed for an
Aggregate aspect shall denote exactly one function with a result type of the
container type, and two parameters of the
same type, called the @i{key type} of the container type.
@drepl
The @i{procedure_}@fa{name} specified for Add_Named or Assign_Indexed for an
Aggregate aspect shall denote exactly one procedure that has three parameters,
the first an @b{in out} parameter of the container type, the second an @b{in}
parameter of a nonlimited type (the @i{key type} of the container type), and
the third, an @b{in} parameter of a nonlimited type that is called the
@i{element type} of the container type.
@dby
The @i{procedure_}@fa{name} specified for Add_Named or Assign_Indexed for an
Aggregate aspect shall denote exactly one procedure that has three parameters,
the first an @b{in out} parameter of the container type, the second an @b{in}
parameter whose type is called the @i{key type} of the container type, and the
third, an @b{in} parameter whose type is called the @i{element type} of the
container type.
@drepl
For an Aggregate aspect, the key type of Assign_Indexed shall be the same
type as that of the parameters of New_Indexed. Additionally, if both
Add_Unnamed and Assign_Indexed are specified, the final parameters shall
be of the same type @emdash the element type of the container type.
@dby
For an Aggregate aspect, neither the element type nor the key type (if any)
of the container type shall be a limited type. Additionally, the key type of
Assign_Indexed shall be the same type as that
of the parameters of New_Indexed, and that type shall be a discrete type. If
both Add_Unnamed and Assign_Indexed are specified, the final parameters shall
be of the same type @emdash the element type of the container type.
None of the subprograms specified for an Aggregate aspect shall have a formal
access parameter, nor an explicitly aliased formal parameter.
ACATS B-Tests should check, for subprograms specified for the Aggregate aspect:
[The following private thread is edited to just relevant parts of messages.
This topic was a small part of a much larger set of questions.]
From: Randy Brukardt
Sent: Tuesday, November 9, 5:59 PM [privately]
(5) 4.3.5(7-9/5) requires the element type to be nonlimited and the key type
to be discrete. These are resolution rules; we typically do not use "nonlimited"
in resolution (Ada 95 did, but that was removed), and probably not "discrete"
in most cases. Should those requirements be Legality Rules instead?
[Aside: One would consider the requirement for Empty to be a constant in this
category as well, although I can't really see any difference in that case
since objects can't be overloaded.]
[Editor's note: AI22-0002-1 eliminated the possibility of Empty being a
constant, since it causes problems for derived types; therefore this aside
is OBE and irrelevant.]
(6) 4.3.5(8/5) requires the key type to be discrete, but 4.3.5(9/5) only
requires it to be nonlimited. Which is intended?? They both can't be right,
since the types are required to be the same, and it doesn't make sense to use
different resolution in the two cases. [Of course, if we answer Yes to (5),
then this becomes moot, since both things will be eliminated from resolution.]
(7) Nothing in 4.3.5(6-9/5) prevents the parameters from being aliased. If
they are aliased, then the Legality of calls (especially for functions) can
depend upon accessibility of expressions. Since the only equivalence is for
Dynamic Semantics, we need to cover Legality somehow. The easiest way would be
to ban aliased parameters (I'm unsure whether that is enough).
(8) In relation to the above, Steve probably will ask if the element type can
be an anonymous access type. (The key type cannot, assuming it is intended to
be required to be discrete, see #6.) The lack of a Legality Rule for
equivalence would bite there again. Probably should ban that as well.
****************************************************************
From: Tucker Taft
Sent: Wednesday, November 10, 5:15 PM [privately]
> 5) 4.3.5(7-9/5) requires the element type to be nonlimited and the key type
> to be discrete. ...
Yes, I suppose we could move at least the nonlimited part to being a legality
rule. I am not sure about the discrete case. It seems friendlier to the user
to keep some of these things as Name resolution rules, as that allows them to
use more overloading when it seems appropriate. Not a big deal either way...
> (6) 4.3.5(8/5) requires the key type to be discrete, but 4.3.5(9/5) only
> requires it to be nonlimited. Which is intended?? They both can't be right,
> since the types are required to be the same, and it doesn't make sense to
> use different resolution in the two cases.
But they are different situations. We certainly don't want to require key
types to be discrete in general, but we do for a container that has a
New_Indexed operation, so that is where we add the requirement to be discrete.
> 7) Nothing in 4.3.5(6-9/5) prevents the parameters from being aliased. If
> they are aliased, then the Legality of calls (especially for functions) can
> depend upon accessibility of expressions. Since the only equivalence is for
> Dynamic Semantics, we need to cover Legality somehow. The easiest way would
> be to ban aliased parameters (I'm unsure whether that is enough).
I am not sure I buy this argument. Even if we define an equivalence in the
Dynamic Semantics, doesn't it also apply to legality rules? If not, I agree
we should say it does apply to Legality Rules as well, or move the equivalence
rule into the Static Semantics.
> (8) In relation to the above, Steve probably will ask if the element type
> can be an anonymous access type. (The key type cannot, assuming it is
> intended to be required to be discrete, see #6.)
As mentioned above, the key type only needs to be discrete if you have a
New_Indexed operation.
> The lack of a Legality Rule for equivalence would bite there again. Probably
> should ban that as well.
I would rather have the equivalence cover legality rules if possible.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, November 10, 8:18 PM [privately]
>> 5) 4.3.5(7-9/5) requires the element type to be nonlimited and the key type
>> to be discrete. ...
>Yes, I suppose we could move at least the nonlimited part to being a legality
>rule. I am not sure about the discrete case. It seems friendlier to the user
>to keep some of these things as Name resolution rules, as that allows them to
>use more overloading when it seems appropriate. Not a big deal either way...
True, not a big deal. But everywhere that we originally used "nonlimited" in
resolution ended up having that dropped with an incompatibility. And it
certainly is possible to imagine a build-in-place aggregate (of course, we'd
need a container for limited elements, don't really have a design for that
yet). The less that we put into resolution, the better.
I view "discrete" here the same way. If at some point in the future, we
allowed user-defined discrete types, we'd have a similar problem.
>> (6) 4.3.5(8/5) requires the key type to be discrete, but 4.3.5(9/5) only
>> requires it to be nonlimited. Which is intended?? They both can't be right,
>> since the types are required to be the same, and it doesn't make sense to
>> use different resolution in the two cases.
>But they are different situations. We certainly don't want to require key
>types to be discrete in general, but we do for a container that has a
>New_Indexed operation, so that is where we add the requirement to be discrete.
So the real issue is that Assign_Indexed (which has to appear with New_Indexed)
should require discrete, while Add_Named only requires nonlimited. That makes
the resolution of Assign_Indexed weaker than New_Indexed even though the
requirements are the same. Ugh. If we move all of those to Legality Rules,
then that problem disappears.
>> 7) Nothing in 4.3.5(6-9/5) prevents the parameters from being aliased. If
>> they are aliased, then the Legality of calls (especially for functions) can
>> depend upon accessibility of expressions. Since the only equivalence is for
>> Dynamic Semantics, we need to cover Legality somehow. The easiest way would
>> be to ban aliased parameters (I'm unsure whether that is enough).
>I am not sure I buy this argument. Even if we define an equivalence in the
>Dynamic Semantics, doesn't it also apply to legality rules? If not, I agree
>we should say it does apply to Legality Rules as well, or move the equivalence
>rule into the Static Semantics.
No, Dynamic Semantic rules never have any effect on static semantics (which
includes legality). There are good reasons for that (Dynamic rules generally
ignore views, for instance, so claiming that they are the same often brings
up a lot of problems).
>> (8) In relation to the above, Steve probably will ask if the element type
>> can be an anonymous access type. (The key type cannot, assuming it is
>> intended to be required to be discrete, see #6.)
>As mentioned above, the key type only needs to be discrete if you have a
>New_Indexed operation.
>> The lack of a Legality Rule for equivalence would bite there again. Probably
>> should ban that as well.
>I would rather have the equivalence cover legality rules if possible.
I explained above why that is generally a bad idea. In both of these cases
(aliased and anonymous access), we'd have to figure out accessibility of the
various temporaries associated with creating an aggregate. I don't want to do
that even if we use some sort of equivalence for other cases. Just reject them
at the top.
Also note that we used an equivalence for user-defined literals, and still
felt it necessary to explicitly ban aliased parameters. Equivalences do not
fix all problems!
****************************************************************
From: Tucker Taft
Sent: Saturday, November 13, 3:44 PM [privately]
...
> I view "discrete" here the same way. If at some point in the future, we
> allowed user-defined discrete types, we'd have a similar problem.
Not sure what a user-defined discrete type could be. But I suppose it is
better to make things less flexible initially (i.e. put them in legality
rules), and then relax the rules later if we decide it is a burden.
...
> So the real issue is that Assign_Indexed (which has to appear with
> New_Indexed) should require discrete, while Add_Named only requires
> nonlimited. That makes the resolution of Assign_Indexed weaker than
> New_Indexed even though the requirements are the same. Ugh. If we move all
> of those to Legality Rules, then that problem disappears.
OK, I'm convinced.
,,,
> No, Dynamic Semantic rules never have any effect on static semantics (which
> includes legality). There are good reasons for that (Dynamic rules generally
> ignore views, for instance, so claiming that they are the same often brings
> up a lot of problems).
Fair enough. We can add restrictions against aliased parameters, etc.
...
> Also note that we used an equivalence for user-defined literals, and still
> felt it necessary to explicitly ban aliased parameters. Equivalences do not
> fix all problems!
OK, I'm convinced.
****************************************************************
From: Tucker Taft
Sent: Tuesday, January 18, 11:17 AM [privately]
...
>The requirements on the classification of the types of the profile of
>subprograms used in an Aggregate aspect should handled by Legality Rules and
>not resolution.
"... should {be} handled by ..."
...
>!wording
>Modify 4.3.5(7/5):
>The procedure_name specified for Add_Unnamed for an Aggregate aspect shall
>denote exactly one procedure that has two parameters, the first an in out
>parameter of the container type, and the second an in parameter of some
>[nonlimited ]type, called the element type of the container type.
This reads awkwardly now: "an in parameter of some type, called the element
type ..." How about:
... an in parameter [of some nonlimited type,]{whose type is} called the
element type of the container type.
>Modify 4.3.5(8/5):
>The function_name specified for New_Indexed for an Aggregate aspect shall
>denote exactly one function with a result type of the container type, and
>two parameters of the same [discrete ]type, with that type being the key
>type of the container type.
Also seems a bit awkward now. How about:
... two parameters of the same [discrete] type, [with that type being]
{called} the key type of the container type.
>Modify 4.3.5(9/5):
>The procedure_name specified for Add_Named or Assign_Indexed for an Aggregate
>aspect shall denote exactly one procedure that has three parameters, the first
>an in out parameter of the container type, the second an in parameter of a
>[nonlimited ]type (the key type of the container type), and the third, an in
>parameter of a [nonlimited ]type that is called the element type of the
>container type.
Again, a bit awkward now. How about:
... the second an in parameter [of a nonlimited ]{whose type is called} [(]the
key type of the container type[)], and the third, an in parameter [of a
nonlimited type that]{whose type} is called the element type of the container
type.
>Modify 4.3.5(11/5):
>For an Aggregate aspect, {neither the element type nor the key type (if any)
>of the container type shall be a limited type or an anonymous access type.
>Additionally, }the key type of Assign_Indexed shall be the same type as
>that of the parameters of New_Indexed{, and that type shall be a discrete
>type}. [Additionally, if]{If} both Add_Unnamed and Assign_Indexed are
>specified, the final parameters shall be of the same type — the element type
>of the container type.
>{None of the subprograms specified for an Aggregate aspect shall have an
>explicitly aliased parameter.}
Perhaps we can move the restriction on anonymous access types into the general
restriction against aliased parameters. Hence, drop the "... or an anonymous
access type" and change the new sentence to be:
{None of the subprograms specified for an Aggregate aspect shall have an
explicitly aliased formal parameter, nor a formal parameter of an anonymous
access type.}
****************************************************************
From: Randy Brukardt
Sent: Wednesday, January 19, 9:36 PM [privately]
>Perhaps we can move the restriction on anonymous access types into the
>general restriction against aliased parameters. Hence, drop the "... or
>an anonymous access type" and change the new sentence to be:
>{None of the subprograms specified for an Aggregate aspect shall have an
>explicitly aliased formal parameter, nor a formal parameter of an anonymous
>access type.}
We CAN move the restriction, but I'm not sure it's a good idea. Written this
way, it seems to be contributing to a common misconception about "access",
which is that it is some sort of modifier (rather than a type declaration).
The restriction is on the key type and the element type, and not really on
parameters. (Of course, the other requirements on the parameters prevent the
other parameters from being access parameters.} Indeed, I wrote it this way at
first and rejected it for the above reasons.
Since we already had a "neither ... nor ..." for the types, it seemed better
to me to put the restriction on the types rather than on the parameters (as
that makes it clear what is really being restricted).
If we do move the restriction, we might as well use the "access parameter"
shorthand (which itself contributes to the misconception):
{None of the subprograms specified for an Aggregate aspect shall have an
explicitly aliased formal parameter, nor a formal access parameter.}
Humm, better to reverse that:
{None of the subprograms specified for an Aggregate aspect shall have a formal
access parameter, nor an explicitly aliased formal parameter.}
This does lend itself better to an AARM note (while the other formulation does
not):
{AARM Reason: Both access parameters and explicitly aliased parameters add
additional requirements on the corresponding actual parameter. These
complicate the description and implementation of container aggregates with
little benefit. Thus we make them illegal. This means neither the element
type nor the key type (if any) of the container type can be an anonymous
access type.}
I went with this latter wording for now, pending further discussion.
****************************************************************