Version 1.1 of ais/ai-00306.txt

Unformatted version of ais/ai-00306.txt version 1.1
Other versions for file ais/ai-00306.txt

!standard 4.3.2 (04)          02-08-28 AI95-00306/00
!standard 4.3.2 (05)
!class binding interpretation 02-08-28
!status received 02-08-07
!qualifier Error
!priority Low
!difficulty Medium
!subject Classwide extension aggregate expressions
!summary
If the ancestor_part of an aggregate is an expression, the expression must have a specific tagged type.
!question
Is the aggregate in the following example illegal?
package Foo is
type T is tagged null record; function F (X : T) return T;
type TT is new T with null record; function F (X : TT) return TT;
end Foo;
package body Foo is
function F (X : T) return T is begin return X; end F;
function F (X : TT) return TT is begin return X; end F;
procedure P (X : in T'Class) is V : TT := (F (X) with null record); -- Error? begin null; end P;
end Foo;
This appears to be legal, because the type of the ancestor expression is T, and the aggregate's type (TT) is derived from T (through one or more record extensions...). So this appears to be legal in spite of the fact that F (X) is a dispatching call.
It seems this should be illegal, as it would require the expression object of T'Class (which might be an object of TT) to implicitly 'truncate' to type T. Usually, this is illegal by 3.9.2(9), but that rule doesn't apply in this case because the expected type is not a specific tagged type. (4.3.2(4) specifies 'some non-limited tagged type'.)
!recommendation
(See summary.)
!wording
( TBD )
!discussion
( TBD )
!ACATS test
A B-Test should be created to check that this rule is checked.
!appendix

From: Gary Dismukes
Sent: Wednesday, August 7, 2002  2:58 PM

One of our developers ran across a problem involving extension aggregates
that raised a semantic issue.  The question is whether the aggregate in
the following example is illegal:

   package Foo is

      type T is tagged null record;
      function F (X : T) return T;

      type TT is new T with null record;
      function F (X : TT) return TT;

   end Foo;


   package body Foo is

      function F (X : T) return T is
      begin
         return X;
      end F;

      function F (X : TT) return TT is
      begin
         return X;
      end F;

      procedure P (X : in T'Class) is
         V : TT := (F (X) with null record);  -- Error?
      begin
         null;
      end P;

   end Foo;

By my reading of the rules this is legal, because the type of the
ancestor expression is T, and the aggregate's type (TT) is derived
from T (through one or more record extensions...).  So this appears
to be legal in spite of the fact that F (X) is a dispatching call.

It seems that this should be illegal, but unless I'm missing something
the RM doesn't disallow it.  If it's agreed that it's currently legal,
then I think that it's desirable to open an AI that would disallow it.
Even if the dynamic semantics of what such an aggregate means are well
defined (though actually I think they're not), this construct seems
harmful to allow since it's almost certainly not what the programmer
intended to write.

What do others think?

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

From: Robert Dewar
Sent: Wednesday, August 7, 2002  4:04 PM

I definitely agree this example should be illegal. In fact I think it *is*
illegal on the grounds that the RM does not say silly things :-) :-)

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

From: Bob Duff
Sent: Wednesday, August 7, 2002  3:36 PM

I think it's illegal by RM-3.9.2(9/1).  F(X) is dynamically tagged,
but it's not a controlling operand.

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

From: Gary Dismukes
Sent: Wednesday, August 7, 2002  4:16 PM

I had looked at that rule, but as far as I can see it doesn't apply in
this case, because the expected type is not "some specific tagged type".
The ancestor expression is "expected to be of any nonlimited tagged type".

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

From: Robert Eachus
Sent: Saturday, August 10, 2002  10:36 AM

For me the interesting question is whether:

V: TT  := TT'((F(X) with null record)); -- Legal?

...is legal.  As far as I can see, it is.  Certainly:

Y: T  := (F(X) with null record);
V: TT := TT(Y);

...is illegal.  So the question is whether an implicit type conversion
should be allowed in this situation.  My feeling is that it should be
explicit, since it is very unclear otherwise whether the user is
expecting TT'(F(X) with null record) or TT(F(X) with null record).

Yeah, I know that most users have a hard time telling which one they
really did mean, but at least we can refuse to hide the choice.  (Yes, I
know that the choices as stated may not be technically legal, take it as
a placeholder for making the case under discussion legal.)  Incidently
GNAT seems to have real problems with this case and variants on it.  I
won't submit a bug report until I know what the right result is, but one
problem seems to be an indefinite loop in type resolution..

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


Questions? Ask the ACAA Technical Agent