AI22-0067-1

!standard 4.3(5)                                        23-08-24  AI22-0067-1/03

!standard 4.3.1(20)

!standard 4.3.2(8/3)

!standard 4.3.3(31)

!standard 4.3.4(21/5)

!standard 4.3.5(53/5)

!standard B.3.3(20/2)

!class binding interpretation 23-03-23

!status Corrigendum 1-2022  23-06-27

!status ARG Approved  6-0-0  23-06-11

!status work item 23-03-23

!priority Low

!difficulty Easy

!qualifier Omission

!subject The nominal subtype of an aggregate

!summary

The nominal subtype of an aggregate is defined. For all cases but delta_aggregates, the nominal subtype is constrained by the discriminants/bounds of the aggregate being defined. For a delta_aggregate, the nominal subtype is that of the base_expression.

!issue

3.3(23/5) starts "At the place where a view of an object is defined, a nominal subtype is associated with the view." 4.3(5) states that an aggregate is an anonymous object, and of course 3.1(7.1/3) says that we always mean “view of object” even when we just say “object”. But nowhere do we define the nominal subtype of an aggregate.

(See Summary.)

!wording

The nominal subtype of a record_aggregate is constrained by the values defined for the discriminants, if any.

The nominal subtype of an extension_aggregate is constrained by the values defined for the discriminants, if any, of the object defined by the aggregate.

The nominal subtype of an array_aggregate (other than a subaggregate) is constrained by the values defined for its bounds and those of any subaggregates.

The nominal subtype of a delta_aggregate is that of its base_expression.

The nominal subtype for an indexed aggregate is the return subtype of the New_Indexed function.  The nominal subtype for any other container aggregate is the return subtype of the Empty function.

Modify B.3.3(20/2):

A view of an unchecked union object (including a type conversion or function call) has inferable discriminants if it has a constrained nominal subtype, unless {either} the object is a component of an enclosing unchecked union object that is subject to a per-object constraint and the enclosing object lacks inferable discriminants{, or the object is a view of an extension_aggregate, and the ancestor_part is an expression of an unchecked union subtype that lacks inferable discriminants}.

!discussion

Most of the rules that use the nominal subtype of an object don't apply to aggregates, at least for Ada 2022.

The only one we could find is rather obscure, involving inferable discriminants of an unchecked union (see B.3.3(20/2)). Thus checks involving aggregates of unchecked unions are ill-defined. For example:

procedure Unchecked_Union_No_Default_Test is

type Precision is (Single_Precision, Multiple_Precision);

type Number (Kind : Precision) is record
case Kind is
when Single_Precision   =>
SP_Value : Long_Float;
when Multiple_Precision =>
MP_Value_Length : Integer;
MP_Value_First  : access Long_Float;
end case;
end record
with Unchecked_Union;

Y : Number (Single_Precision); -- Inferable discriminant
begin
Y.SP_Value := 55.7;
if Y = (Single_Precision, 45.6) then -- (1)
else
end if;
end Unchecked_Union_No_Default_Test;

To determine whether (1) raises Program_Error, for the item in B.3.3(23/2):

• Evaluation of the predefined equality operator for an unchecked union type if either of the operands lacks inferable discriminants.

We need to know if the aggregate has inferable discriminants, and to answer that question, we need to know the nominal subtype of the aggregate. And we really don't want (1) raising Program_Error, since the discriminants involved are known and static.

So we could potentially fix both of the identified problems by specific rules; carving out an exception to the general rule that objects have a nominal subtype, and adding a specific rule about aggregates that are unchecked unions.

However, we have a number of proposals for composite case statements in the pipeline. Assuming that coverage would work the same for those as it does for discrete subtypes, the nominal subtype would become much more important. And it would not be surprising to find/create other cases where the nominal subtype is required.

As such, we recommend that the nominal subtype be defined, and it be defined as tightly as possible, so that the unchecked union case and the case statement case require only what is necessary. (Simply defining all aggregates as unconstrained would not be a good idea.)

As can be seen from the proposed !wording section, we have defined the nominal subtypes for all but delta_aggregates to be constrained by the discriminants/bounds of the aggregate object being defined. Delta_aggregates inherit the nominal subtype of their base expression, whatever that happens to be.

!ACATS test

ACATS tests might be necessary to check that the appropriate effects occur. The example given in the !discussion probably should be an ACATS C-Test, for instance.

!appendix

The original mail on this topic is filed in AI12-0066-1.