Version 1.5 of ai12s/ai12-0428-1.txt

Unformatted version of ai12s/ai12-0428-1.txt version 1.5
Other versions for file ai12s/ai12-0428-1.txt

!standard 4.1.6(2/3)          21-06-07 AI12-0428-1/03
!standard 4.1.6(3/3)
!standard 5.5.1(8/5)
!class binding interpretation 21-05-21
!status Amendment 1-2012 21-06-07
!status WG9 Approved 22-06-22
!status ARG Approved 13-0-2 21-06-03
!status work item 21-05-21
!status received 21-05-21
!priority Low
!difficulty Easy
!qualifier Error
!subject "Same declaration list" requirement too strong for private types
!summary
The requirement that the function(s) specified for a Constant_Indexing or Variable_Indexing shall be in the same declaration list is too strong for the completion of a private type.
!question
Two Ada 2012 implementations get different results on the following example (distilled from ACATS test B416001):
procedure B416001 is
type Ref (Int_Ref : access Integer) is null record with Implicit_Dereference => Int_Ref; Null_Ref : constant Ref := (Int_Ref => null);
package Invalid_Indexing_Types is type Priv_2 is private; function Priv_2_Func (P : Priv_2; Index : Positive) return Ref is (Null_Ref); private type Priv_2 is tagged null record with Variable_Indexing => Priv_2_Func; -- OK. end Invalid_Indexing_Types;
...
One of the compilers matches the result suggested by the test author. The other compiler rejects the line marked "OK." referring to 4.1.6(3/3) and saying that Priv_2_Func is declared in the wrong declaration list.
Is the test correct? (Yes.)
!recommendation
(See Summary.)
!wording
Modify 4.1.6(2/3):
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T{, or the declaration completed by T,} is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access-to-constant parameter with designated type T or T'Class.
Modify 4.1.6(3/3):
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T{, or the declaration completed by T,} is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access parameter with designated type T or T'Class. All such functions shall have a return type that is a reference type (see 4.1.5), whose reference discriminant is of an access-to-variable type.
Modify 5.5.1(8/5):
This aspect is specified by a name that denotes exactly one function declared immediately within the same declaration list in which T{, or the declaration completed by T,} is declared, whose first parameter is of type T or T'Class or an access parameter whose designated type is type T or T'Class, whose other parameters, if any, have default expressions, and whose result type is an iterator type. This function is the default iterator function for T. Its result subtype is the default iterator subtype for T. The iteration cursor subtype for the default iterator subtype is the default cursor subtype for T. This aspect is inherited by descendants of type T (including T'Class).
!discussion
4.1.6(3/3) says:
Variable_Indexing
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access parameter with designated type T or T'Class. All such functions shall have a return type that is a reference type (see 4.1.5), whose reference discriminant is of an access-to-variable type.
The important part here is the requirement that the function is defined in the "same declaration list as T". That of course raises the question of where Priv_2 is defined.
Careful study of the rules suggests that the wording says that the type is declared in the declaration list of the visible part of the package. For purposes of this sort of "what declaration list is it declared in" question, a completion only declares a new view of an already existing type (as opposed to declaring the type).
The 4.1.6(3/3) wording seems to have an implicit assumption that a type is declared in a single declaration list and that indicates that we really are talking about a declaring a type (as opposed to declaring a view of a type).
Note that AARM 3.9.2(1.a.1/2), confirms this interpretation in the context of stream-oriented attributes.
With this understanding of the wording, then trying to hide indexing as follows:
package Invalid_Indexing_Types is type Priv_X is private; private type Priv_X is tagged null record with Variable_Indexing => Priv_X_Func; -- !!! function Priv_X_Func (P : Priv_X; Index : Positive) return Ref is (Null_Ref); end Invalid_Indexing_Types;
...is illegal, as the operation is not in the same declaration list as the type. This seems to be a perfectly reasonable thing to do, so it seems pretty clear that the language is broken.
Note that the requirement is simply intended to ensure that the specified function(s) have the same accessibility (lifetime) as the type, so that they always exist when the type does. (And, for functions with specific type parameters, that they are primitive.) This means that anything in the same package specification should be allowed (subject to visibility; one cannot use private operations in the visible part; that's ensured by basic rules of aspect specifications and does not need to be mentioned here).
---
Default_Iterator uses similar wording, and was fixed in a corresponding manner.
!corrigendum 4.1.6(2/3)
Replace the paragraph:
Constant_Indexing
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access-to-constant parameter with designated type T or T'Class.
by:
Constant_Indexing
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T, or the declaration completed by T, is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access-to-constant parameter with designated type T or T'Class.
!corrigendum 4.1.6(3/3)
Replace the paragraph:
Variable_Indexing
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access parameter with designated type T or T'Class. All such functions shall have a return type that is a reference type (see 4.1.5), whose reference discriminant is of an access-to-variable type.
by:
Variable_Indexing
This aspect shall be specified by a name that denotes one or more functions declared immediately within the same declaration list in which T, or the declaration completed by T, is declared. All such functions shall have at least two parameters, the first of which is of type T or T'Class, or is an access parameter with designated type T or T'Class. All such functions shall have a return type that is a reference type (see 4.1.5), whose reference discriminant is of an access-to-variable type.
!corrigendum 5.5.1(8/5)
Replace the paragraph:
Default_Iterator
This aspect is specified by a name that denotes exactly one function declared immediately within the same declaration list in which T is declared, whose first parameter is of type T or T'Class or an access parameter whose designated type is type T or T'Class, whose other parameters, if any, have default expressions, and whose result type is an iterator type. This function is the default iterator function for T. Its result subtype is the default iterator subtype for T. The iteration cursor subtype for the default iterator subtype is the default cursor subtype for T. This aspect is inherited by descendants of type T (including T'Class).
by:
Default_Iterator
This aspect is specified by a name that denotes exactly one function declared immediately within the same declaration list in which T, or the declaration completed by T, is declared, whose first parameter is of type T or T'Class or an access parameter whose designated type is type T or T'Class, whose other parameters, if any, have default expressions, and whose result type is an iterator type. This function is the default iterator function for T. Its result subtype is the default iterator subtype for T. The iteration cursor subtype for the default iterator subtype is the default cursor subtype for T. This aspect is inherited by descendants of type T (including T'Class).
!ASIS
No ASIS effect.
!ACATS test
ACATS test B416001 already has examples of this (commented out for now); those can be replaced for Ada 202x.
!appendix

[From WG 9 issue #174]

I was testing a new (to me) compiler with the ACATS and I ran across one test 
(B416001) that gets different results on different compilers and now believe 
that it is the language that is wrong.

Just showing the declarations for the case in question:

procedure B416001 is

  type Ref (Int_Ref : access Integer) is null record
     with Implicit_Dereference => Int_Ref;
  Null_Ref : constant Ref := (Int_Ref => null);

  package Invalid_Indexing_Types is
     type Priv_2 is private;
     function Priv_2_Func
        (P : Priv_2; Index : Positive) return Ref is (Null_Ref);
  private
     type Priv_2 is tagged null record
        with Variable_Indexing => Priv_2_Func;     -- OK.
  end Invalid_Indexing_Types;

...

One of the compilers matches the result suggested by the test author. The 
other compiler rejects the line marked "OK." referring to 4.1.6(3/3) and
saying that Priv_2_Func is declared in the wrong declaration list.

4.1.6(3/3) says:

Variable_Indexing

This aspect shall be specified by a name that denotes one or more functions
declared immediately within the same declaration list in which T is declared.
All such functions shall have at least two parameters, the first of which is
of type T or T'Class, or is an access parameter with designated type T or
T'Class. All such functions shall have a return type that is a reference type
(see 4.1.5), whose reference discriminant is of an access-to-variable type.

The important part here is the requirement that the function is defined in 
the "same declaration list as T". That of course raises the question of 
where Priv_2 is defined.

Steve Baird provided the answer to that question by noting:

I agree that the RM is unfortunately vague on that point, but given the current 
wording I would say that the type is declared in the declaration list of the 
visible part of the package. For purposes of this sort of "what declaration 
list is it declared in" question, a completion only declares a new view of 
an already existing type (as opposed to declaring the type).

The current wording seems to have an implicit assumption that a type is 
declared in a single declaration list and, to me, that indicates that we 
really are talking about a declaring a type (as opposed to declaring a view 
of a type).

FWIW, see AARM 3.9.2(1.a.1/2), which confirms this interpretation in the 
context of stream-oriented attributes.

Of course, if we assume Steve's interpretation is correct, then trying to 
hide indexing via:

  package Invalid_Indexing_Types is
      type Priv_X is private;
  private
      type Priv_X is tagged null record
        with Variable_Indexing => Priv_X_Func;     -- !!!
      function Priv_X_Func
        (P : Priv_X; Index : Positive) return Ref is (Null_Ref);
  end Invalid_Indexing_Types;

...is illegal, as the operation is not in the same declaration list as the 
type. This seems to be a perfectly reasonable thing to do and it poses no 
semantic problems, so it seems pretty clear that the language is broken.

After some additional discussion, Tucker Taft proposed the following 
rewording:

This aspect shall be specified by a name that denotes one or more functions 
declared immediately within the same declaration list in which T{, or the 
declaration completed by T,} is declared.

Constant_Indexing has the same wording and needs the same fix in 4.1.6(2/3).

****************************************************************

Questions? Ask the ACAA Technical Agent