Version 1.4 of ai05s/ai05-0133-1.txt

Unformatted version of ai05s/ai05-0133-1.txt version 1.4
Other versions for file ai05s/ai05-0133-1.txt

!standard 8.6(17)          09-03-09 AI05-0133-1/02
!class ramification 09-01-24
!status WG9 Approved 09-06-12
!status ARG Approved 8-0-1 09-02-21
!status work item 09-01-24
!status received 08-12-22
!priority Low
!difficulty Medium
!qualifier Clarification
!subject Extending a type with a self-referencing discriminant constraint on a component
!summary
It is legal to extend types that have a component with a self-referencing access initializing a discriminant constraint.
!question
Is this code legal? (Yes.)
package Pack1 is
type Root is tagged;
type Rec2 (D : access Root) is tagged limited null record;
type Root is tagged limited record Z : Rec2 (Root'access); end record;
type Child is new Root with record F1 : Integer; end record;
end Pack1;
If you say
Obj : aliased Child;
Obj will have a component Z. What is its discriminant (Obj.Z.D)? The rules about current instances (8.6(17)) say that the name "Root" refers to the object that causes the discriminant to be evaluated, namely Obj. So the discriminant would be Obj'Access.
But the rules also say that when Obj'Access appears, there has to be an expected type, and that if this expected type is an anonymous access type with designated type D, the type of the object has to be either D'Class or a type covered by D. Here, D is "Root", and since it's a specific type, it covers only itself, and thus it should be illegal for Obj'Access to be used as the discriminant of Z. Note that if you took out the component Z, you would not be able to write:
Obj : aliased Child; My_Rec2 : Rec2 (Obj'access);
So how could Obj'Access be legal for the component Z? (See discussion.)
!recommendation
(See Summary.)
!wording
None needed.
!discussion
The example is legal.
The questioner is confusing the static and dynamic semantics of the code. In particular, the meaning of Root'Access in the declaration of component Z is resolved when the type Root is declared. It is determined at that time to be an access to the enclosing object, and the types are correct.
When the type Child is declared, type resolution is performed on the new components, but the meaning of the parent type is unchanged. If that wasn't true, all kinds of weird effects could be generated. For instance:
package Pack2 is
function F return Natural;
type Root is tagged limited record C1 : Natural := F; end record;
end Pack2;
package Pack2.Child is function F return Natural;
type Child is new Root with record C2 : Natural := F; end record;
end Pack2.Child;
Obj : Pack2.Child.Child;
Obj.C1 will be initialized with Pack2.F, while Obj.C2 will be initialized with Pack2.Child.F. If resolution was done again on the parent part of Child, Obj.C1 would have been initialized with Pack2.Child.F. That would be bad, as the creator of Pack2 knows nothing about Pack2.Child (and, indeed, if private types are involved, the reverse could also be true).
On the other hand, the dynamic semantics are executed for each object as they are created. So, in our example above, the functions are called at the point of the declaration of the object, even though the specific functions that are called are determined earlier.
The same thing happens in the example in the question. Root'Access has been determined to denote the enclosing object, but exactly which object is of course determined at runtime. Thus, the object declaration creates an access of a type that couldn't be created explicitly, but there is no semantic problem with the creation of such an access (all objects of type Child have a Root portion).
It is merely a curiosity that while it is obvious that Obj.Z.D has the value of Obj.Access, you cannot compare those directly. (You could write Obj.Z.D = Root'Class (Obj)'Access to compare these values.)
!ACATS Test
No new ACATS tests are needed.
!appendix

!topic Type extension from record with self-referential discriminant constraint
!reference RM 3.10.2, 8.6
!from Adam Beneschan 08-12-22
!discussion

I'm not clear on the legality of this code:

    package Pack1 is

        type Root is tagged;

        type Rec2 (D : access Root) is tagged limited null record;

        type Root is tagged limited record
            Z : Rec2 (Root'Access);
        end record;

        type Child is new Root with record
            F1 : Integer;
        end record;

    end Pack1;

If you say

    Obj : aliased Child;

Obj will have a component Z.  What is its discriminant (Obj.Z.D)?  The rules about
current instances (8.6(17)) say that the name "Root" refers to the object that
causes the discriminant to be evaluated, namely Obj.  So the discriminant would
be Obj'Access.

But the rules also say that when Obj'Access appears, there has to be an expected
type, and that if this expected type is an anonymous access type with designated
type D, the type of the object has to be either D'Class or a type covered by D.
Here, D is "Root", and since it's a specific type, it covers only itself, and thus
it should be illegal for Obj'Access to be used as the discriminant of Z.  (Note
that if you took out the component Z, you would not be able to write:

    Obj     : aliased Child;
    My_Rec2 : Rec2 (Obj'Access);

So how could Obj'Access be legal for the component Z?)

This wouldn't be an issue of Rec2 were declared:

    type Rec2 (D : access Root'Class) is tagged limited null record;

this is clearly legal.

I should also note that I wouldn't necessarily have a problem with an implicit type
conversion to the "access Root" type; this would mean that the program wouldn't be
able to access extension fields (such as F1) through D, but it could still access
all fields of the parent. Syntactically, though, Ada doesn't allow type conversions
unless you have a type you're converting *from*; so you could say

    My_Rec2 : Rec2 (Root_Acc (Child_Acc' (Obj'Access)));

(assuming type Root_Acc is access all Root, similarly for Child_Acc), but there's
no way to do this without named access types (3.10.2(2)).
So without some explicit RM language to handle this case, I don't see any basis
for allowing the definition of Child, or any other type extension of Root.  

Is this the intent?  It really seems to me that it isn't.

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


Questions? Ask the ACAA Technical Agent