pat-rogers / Ada-202x-WG9-Informal-Review

This is the place for WG 9 members to submit informal comments on the 202x source document. (This is not the formal ballot that WG 9 will hold later in the process.)
0 stars 0 forks source link

4.1.6(3/3) - Rule does not allow reasonable specifications for private types #174

Open ARG-Editor opened 3 years ago

ARG-Editor commented 3 years ago

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).

ARG-Editor commented 3 years ago

This issue has been written up as AI12-0428-1.