AI22-0028-1

!standard B.3.3(22/2)                                    22-04-25  AI22-0028-1/03

!standard B.3.3(23/2)

!standard B.3.3(24/2)

!class binding interpretation 22-01-24

!status work item 22-01-24

!status received 21-11-16

!priority Very_Low

!difficulty Easy

!qualifier Clarification

!subject Program_Error for unchecked union equality

!summary

Program_Error is not raised when equality is checked if a type with a

user-defined equality encloses the unchecked union component.

!issue

It seems that when we changed the rules on equality to make record types use

their primitive equality everywhere, we didn't adjust the rules for equality

on unchecked unions.  Here are the relevant rules from B.3.3:

   22/2 Program_Error is raised in the following cases:

   23/2    * Evaluation of the predefined equality operator for an unchecked

             union type if either of the operands lacks inferable

             discriminants.

   24/2    * Evaluation of the predefined equality operator for a type which

             has a subcomponent of an unchecked union type whose nominal

             subtype is unconstrained.

Paragraph (24/2) does not make sense if there is a user-defined equality operator for the unchecked union type itself, or if the unchecked union subcomponent is part of an enclosing subcomponent that has a user-defined equality operator. We only need to have Program_Error raised if the predefined equality operator of the unchecked union type would be "reachable" from the equality operator for the enclosing object.

!recommendation

(See Summary.)

!wording

Delete B.3.3(24/2):

* Evaluation of the predefined equality operator for a type which

has a subcomponent of an unchecked union type whose nominal

subtype is unconstrained.

!discussion

Note that the current rule requires raising Program_Error in cases where there is no problem, but does not allow anything problematic. As such, we do not want to incur any significant overhead to fix this problem.

The intent of the original rule is that it can be checked at compile-time outside of shared generic implementations (see AI95-00216-01). Ultimately, after considering various ways of accomplishing this, we opted for the easiest approach, namely deleting paragraph 24/2 completely, while leaving 23/2 as is. Dropping the part about inferable discriminants would be incompatible, as equality of constrained components would suddenly start raising Program_Error (the worst kind of incompatibility, where previously correct code would start raising an exception). Compilers can certainly provide a warning if they detect that a Program_Error is inevitable, but mandating a hard-to-define check was not deemed worthwhile.

!ACATS test

An ACATS C-Test should be constructed to check that a user-defined equality for an unchecked union type (or for an enclosing record type) does not cause Program_Error to be raised.

!appendix

From: Tucker Taaft

Sent: Tuesday, November 16, 2021  12:27 PM

It seems that when we changed the rules on equality to make record types use

their primitive equality everywhere, we didn't adjust the rules for equality

on unchecked unions.  Here are the relevant rules from B.3.3:

   22/2 Program_Error is raised in the following cases:

   23/2    * Evaluation of the predefined equality operator for an unchecked

             union type if either of the operands lacks inferable

             discriminants.

   24/2    * Evaluation of the predefined equality operator for a type which

             has a subcomponent of an unchecked union type whose nominal

             subtype is unconstrained.

Paragraph (23/2) seems fine, but paragraph (24/2) does not make sense any more

if there is a user-defined equality operator for the unchecked union type

itself, or if the unchecked union subcomponent is part of an enclosing

subcomponent that has a user-defined equality operator.  We only want to have

Program_Error if the predefined equality operator of the unchecked union type

would be "reachable" from the equality operator for the enclosing object.

I presume we wanted to allow the implementation to raise Program_Error

immediately, rather than doing some of the equality checks and then noticing

it had reached an unchecked union part of the objects being compared.  But

this seems like an unnecessary permission, and trying to combine the intent of

this permission with the new rules on use of primitive equality everywhere for

record types seems just too complicated.

Looking back at the original AI on Unchecked_Union, it actually includes

discussion of paragraph (24/2), and the intent was to make this a compile-time

check (at least outside of shared generics).  So perhaps we should come up

with some wording that works at compile time, but it is probably going to

require some "interesting" wording.

E.g.:

*  Evaluation of the predefined equality operator for a composite type that

   has a subcomponent of an unchecked union type, where the unchecked union

   and each of the types that enclose it within this outer composite type

   either lacks a user-defined primitive equality operator, or is an array

   type;

Not great, but should be checkable at compile time...