Version 1.4 of ais/ai-00332.txt

Unformatted version of ais/ai-00332.txt version 1.4
Other versions for file ais/ai-00332.txt

!standard 8.6 (27)          04-12-02 AI95-00332/04
!class binding interpretation 03-07-25
!status Amendment 200Y 04-12-02
!status ARG Approved 8-0-2 04-11-21
!status work item 03-07-25
!status received 03-03-17
!qualifier Omission
!priority Low
!difficulty Medium
!subject Resolution of qualified expressions and object renamings
!summary
Access attributes, character literals, and other constructs requiring a single expected type can be used as the operand of a qualified expression and can be renamed.
!question
Which of the following allocators is legal? (Neither.)
procedure test47 is type T1 is tagged null record;
type T1_Acc is access T1; type T1_Class_Acc is access T1'Class;
procedure Proc (X : in T1; Y : in T1'Class) is P1 : T1_Acc; P2 : T1_Class_Acc; begin P1 := new T1' (Y); -- IS THIS LEGAL? (No.) P2 := new T1'Class' (X); -- IS THIS LEGAL? (No.) end Proc;
begin null; end test47;
The language of 4.7(3) says the operand "shall resolve to" be of the type determined by the subtype mark, as opposed to most of the other name resolution rules that talk about what the expected type is. This seems to mean that the operand (or more strictly, an acceptable interpretation of the operand) has to be of the same type determined by the subtype mark. This would seem to mean that both are illegal, because Y resolves to T1'Class instead of T1, and X resolves to T1 instead of T1'Class.
Is that the correct interpretation? (Yes.)
Another question regarding qualified expressions:
type T1 is record ... end record; type Acc_1 is access all T1; type Acc_2 is access all T1;
X : aliased T1;
procedure Some_Proc (Param : in Acc_1); procedure Some_Proc (Param : in Acc_2);
Some_Proc (Acc_1' (X'access)); -- OK (Yes.) Some_Proc (Acc_1' (null)); -- OK (Yes.)
Are these qualified expression legal? (Yes.)
One possible reading would say that it isn't, because 3.10.2(2) says that the type of X'Access is determined by the expected type, and the Name Resolution Rules for a qualified expression don't specify what the expected type of the operand is (again, unlike the Name Resolution Rules for many other Ada constructs). So if there's no expected type, 3.10.2(2) doesn't know what type X'Access should have. The same reading holds for 4.2(2).
!recommendation
(See Wording.)
!wording
Replace 8.6(27) by:
When a construct is one that requires that its expected type be a single type in a given class, the type of the construct shall be determinable solely from the context in which the construct appears, excluding the construct itself, but using the requirement that it be in the given class. Furthermore, the context shall not be one that expects any type in some class that contains types of the given class; in particular, the construct shall not be the operand of a type_conversion.
AARM Note:
The part of the first sentence after the semicolon serves to define the "expected type" for constructs that don't have one (like qualified expressions and renames). Otherwise, such constructs wouldn't allow aggregates, 'Access, and so on.
!discussion
Clearly we want the Access attribute, character literals, and so on, to work in qualified expressions. The entire point of qualified expressions is to resolve ambiguity in expressions, and the purpose would be severely compromised if some types of expressions could not be used in them.
However, the "expected type" of the operand of a qualified expression is not defined. In order for the resolution rules for the above cases to work, the expected type needs to be defined. These are just some of the cases where the expected type is used in other rules.
Just changing the definition of qualified expression doesn't work, however. First, there are other such constructs for objects (object renames and selected components come to mind). Fixing every one of them seems prohibitive. Second, just defining the expected type of a qualified expression would trigger the rules of 8.6(22-25). But we definitely do not want the operand of a qualified expression to be a classwide type if the qualifying type is a specific type. Moreover, a legality rule would make some qualified expressions ambiguous, which would make qualified expressions less useful for their primary purpose of eliminating ambiguity.
The new wording solves the problem, in that it only mentions "expected type" as part of identifying the case we are talking about, but doesn't require that the context actually provide such an expected type. The trailing phrase "the type of the construct is then this single expected type" was dropped, as it seems unnecessary with this new wording. The second sentence rules out cases where any type in a class is expected, which might require overload resolution to deal with cases where there just happens to be only one such type in scope.
!corrigendum 8.6(27)
Replace the paragraph:
When the expected type for a construct is required to be a single type in a given class, the type expected for the construct shall be determinable solely from the context in which the construct appears, excluding the construct itself, but using the requirement that it be in the given class; the type of the construct is then this single expected type. Furthermore, the context shall not be one that expects any type in some class that contains types of the given class; in particular, the construct shall not be the operand of a type_conversion.
by:
When a construct is one that requires that its expected type be a single type in a given class, the type of the construct shall be determinable solely from the context in which the construct appears, excluding the construct itself, but using the requirement that it be in the given class. Furthermore, the context shall not be one that expects any type in some class that contains types of the given class; in particular, the construct shall not be the operand of a type_conversion.
!ACATS test
Existing ACATS tests test resolution of qualified expressions, including various kinds of literals.
!appendix

!topic Qualified expressions, meaning of "resolve to"
!reference RM95 4.7(3), AARM95 4.8(4a), RM95 3.10.2(24)
!from Adam Beneschan 03-17-03
!discussion

Which of the following allocators is legal?

    procedure test47 is
        type T1 is tagged null record;

        type T1_Acc is access T1;
        type T1_Class_Acc is access T1'Class;

        procedure Proc (X : in T1; Y : in T1'Class) is
            P1 : T1_Acc;
            P2 : T1_Class_Acc;
        begin
            P1 := new T1' (Y);        -- IS THIS LEGAL?
            P2 := new T1'Class' (X);  -- IS THIS LEGAL?
        end Proc;

    begin
        null;
    end test47;

I have been going back and forth on this question, and now I'm not
sure what the answer is.  The language of 4.7(3) says the operand
"shall resolve to" be of the type determined by the subtype mark, as
opposed to most of the other name resolution rules that talk about
what the expected type is.  This seems to mean that the operand (or
more strictly, an acceptable interpretation of the operand) has to be
of the same type determined by the subtype mark.  This would seem to
mean that both are illegal, because Y resolves to T1'Class instead of
T1, and X resolves to T1 instead of T1'Class.

Is that the correct interpretation?  If not, why not?

AARM 4.8(4a) says,

    Ramification: For example, ... new S'Class ... (with no
    initialization expression) is illegal, but ... new S'Class'(X)
    ... is legal, and takes its tag and constraints from the initial
    value X. (Note that the former case cannot have a constraint.)

Although this paragraph doesn't say specifically what X is, the
implication seems to be that X can be a value whose type is any type
in S'Class, and that the allocator takes its tag from the initial
value.  In other words the implication is that something like the
assignment to P2 in the above example should be legal, which
contradicts the interpretation I gave above.

Another question regarding qualified expressions:

    type T1 is record ... end record;
    type Acc_1 is access all record;
    type Acc_2 is access all record;

    X : aliased T1;

    procedure Some_Proc (Param : in Acc_1);
    procedure Some_Proc (Param : in Acc_2);

    Some_Proc (Acc_1' (X'Access));

Is this qualified expression legal?  One possible reading would say
that it isn't, because 3.10.2(24) says that the type of X'Access is
determined by the expected type, and the Name Resolution Rules for a
qualified expression don't specify what the expected type of the
operand is (again, unlike the Name Resolution Rules for many other Ada
constructs).  So if there's no expected type, 3.10.2(24) doesn't know
what type X'Access should have.

Sorry if this all seems pedantic, but I'm genuinely confused here, and
am wondering if some clarification in the RM (or AARM) is warranted.
I appreciate any assistance anyone can give.

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

From: Randy Brukardt
Sent: Monday, March 17, 2003 11:52 PM

> ...The language of 4.7(3) says the operand
> "shall resolve to" be of the type determined by the subtype mark, as
> opposed to most of the other name resolution rules that talk about
> what the expected type is.  This seems to mean that the operand (or
> more strictly, an acceptable interpretation of the operand) has to be
> of the same type determined by the subtype mark.  This would seem to
> mean that both are illegal, because Y resolves to T1'Class instead of
> T1, and X resolves to T1 instead of T1'Class.

"Shall resolve to" is commonly used in the RM (I found 30 pages using it in
the AARM - check the search page at
http://www.adaic.com/standards/95aarm/html/AA-SRCH.html). I believe that
8.6(14) is intended to define what "shall resolve to" means, although that
description seems weak to me - and the AARM notes are no help. However, I
believe the intent is that it resolves exactly to the type (the normal rules
about class-wide types don't apply here).

Thus, your original examples are illegal.

> Although this paragraph doesn't say specifically what X is, the
> implication seems to be that X can be a value whose type is any type
> in S'Class, and that the allocator takes its tag from the initial
> value.  In other words the implication is that something like the
> assignment to P2 in the above example should be legal, which
> contradicts the interpretation I gave above.

No, X has to have type S'Class. But of course the actual type of the object
X could be any type in S'Class. That's just normal class-wide programming. I
don't see any implication of the type of X here.

>...
>     Some_Proc (Acc_1' (X'Access));
>
> Is this qualified expression legal?  One possible reading would say
> that it isn't, because 3.10.2(24) says that the type of X'Access is
> determined by the expected type, and the Name Resolution Rules for a
> qualified expression don't specify what the expected type of the
> operand is (again, unlike the Name Resolution Rules for many other Ada
> constructs).  So if there's no expected type, 3.10.2(24) doesn't know
> what type X'Access should have.

That does appear to be a hole, although you're looking at the wrong
paragraph: it's 3.10.2(2) that defines this. (Note that 3.10.2(2) is
substantially changed by AI-235, but still has the expected type wording).
So it does appear that some connection between expected type and "shall
resolve to" is necessary. But perhaps someone else can explain the
(invisible) connection.

> Sorry if this all seems pedantic, but I'm genuinely confused here, and
> am wondering if some clarification in the RM (or AARM) is warranted.
> I appreciate any assistance anyone can give.

Well, we do need to be pedantic from time-to-time. It's not clear to me that
the wording adquately embodies the intent. It is clear that 4.7(3) couldn't
use "expected type", because that would allow class-wide matching, and that
is not desired for qualified expressions. But I don't see any way to connect
"shall resolve to" (which doesn't seem to be talking about types) to
"expected types".

I hope that Bob or Tuck enlightens us as to how the wording actually matches
the intent. :-)

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

From: Tucker Taft
Sent: Tuesday, March 18, 2003 10:50 AM

I think we were a bit fast and loose with the phrase
"single expected type."  A qualified expression definitely
creates an "expectation" for a "single" type, but doesn't
use the term "expected type" itself (for good reason, as
Randy points out, that would kick in the class-wide matching
rules).  So 8.6(27) should probably be clarified to explicitly
included a qualified expression as a construct that satisfies
the requirement for a "single expected type."

...
> I hope that Bob or Tuck enlightens us as to how the wording actually matches
> the intent. :-)

I don't know if I helped, but I gave it a try...

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

From: Christoph Grein
Sent: Thursday, March 20, 2003  5:25 AM

> Thus, your original examples are illegal.

Just for information - hope someone from ACT listens, Gnat 3.16a:

    procedure test47 is
        type T1 is tagged null record;

        type T1_Acc is access T1;
        type T1_Class_Acc is access T1'Class;

        procedure Proc (X : in T1; Y : in T1'Class) is
            P1 : T1_Acc;
            P2 : T1_Class_Acc;
        begin
            P1 := new T1' (Y);        -- IS THIS LEGAL?  Gnat says yes.  not OK
            P2 := new T1'Class' (X);  -- IS THIS LEGAL?  Gnat says no.   OK
            -- I think the effect of the above illegal statements
            -- can be achieved like so:
            P1 := new T1'(t1 (Y));
            P2 := new T1'Class'(t1'class (X));
        end Proc;

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

From: Tucker Taft
Sent: Thursday, March 20, 2003 10:13 AM

For what it's worth, I have attached the listing
produced by the AdaMagic front end for this example.
It rejects both of the illegal allocators.

---

Source file: qualified.ada   Thu Mar 20 11:11:07 2003

    1   procedure qualified is
    2         type T1 is tagged null record;
    3
    4         type T1_Acc is access T1;
    5         type T1_Class_Acc is access T1'Class;
    6
    7         procedure Proc (X : in T1; Y : in T1'Class) is
    8             P1 : T1_Acc;
    9             P2 : T1_Class_Acc;
   10         begin
   11             P1 := new T1' (Y);        -- IS THIS LEGAL?  Gnat says yes.  not OK
                                 *
*****Error: LRM:8.6(28) Expression has no possible interpretation as an
*****        expression of the type T1, Continuing
   12             P2 := new T1'Class' (X);  -- IS THIS LEGAL?  Gnat says no.   OK
                                       *
*****Error: LRM:8.6(28) Expression has no possible interpretation as an
*****        expression of the type T1'Class, Continuing
   13             -- I think the effect of the above illegal statements
   14             -- can be achieved like so:
   15             P1 := new T1'(t1 (Y));
   16             P2 := new T1'Class'(t1'class (X));
   17         end Proc;
   18
   19    begin
   20         null;
   21    end;

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

From: Randy Brukardt
Sent: Friday, July 25, 2003  5:42 PM

Janus/Ada also rejects both allocators.

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

From: Randy Brukardt
Sent: Friday, July 25, 2003  7:13 PM

I've been working on the big backlog of boring AIs. I wrote up this AI, but
am not very happy with the wording. Perhaps someone has a better suggestion.

Anyway, here is the relevant question from the AI. (There is another
question, which is why I'm not appending the AI itself.)

---

    type T1 is record ... end record;
    type Acc_1 is access all record;
    type Acc_2 is access all record;

    X : aliased T1;

    procedure Some_Proc (Param : in Acc_1);
    procedure Some_Proc (Param : in Acc_2);

    Some_Proc (Acc_1' (X'Access)); -- OK (Yes.)
    Some_Proc (Acc_1' (null)); -- OK (Yes.)

Are these qualified expression legal? (Yes.)

One possible reading would say that it isn't, because 3.10.2(2) says that the
type of X'Access is determined by the expected type, and the Name Resolution
Rules for a qualified expression don't specify what the expected type of the
operand is (again, unlike the Name Resolution Rules for many other Ada
constructs).  So if there's no expected type, 3.10.2(2) doesn't know what type
X'Access should have. The same reading holds for 4.2(2).

---

Clearly, we want these cases to work, so the only question is what the
wording should be to fix the whole. Tucker suggested changing 8.6(27), and
since I don't see any other uses of "expected type" for the results of
expressions, I did that.

Replace 8.6(27) by:

When the expected type for a construct is required to be a @i<single> type in a
given class, the type expected for the construct shall be determinable solely
from the context in which the construct appears, excluding the construct
itself, but using the requirement that it be in the given class; the type of
the construct is then this single expected type. In particular, when a single
type is required, the operand of a @fa<qualified_expression> identifies a
single type (namely, the type specifed by the @fa<subtype_mark>), and that type
is the expected type of the operand. Furthermore, the context shall not be one
that expects any type in some class that contains types of the given class; in
particular, the construct shall not be the operand of a @fa<type_conversion>.

The sentence starting with "In particular" is new.

I'm not very happy with this wording. We're defining expected type for the
operands of qualified expressions only when a single type is needed.
Otherwise, there is no expected type.

This seems necessary because in other cases the rules of 8.6(22-25) would be
triggered, and we definitely don't want them used for the operands of
qualified expressions.

An alternative would be to replace 4.7(3) by:

The expected type of the @i<operand> (the @fa<expression> or @fa<aggregate>) is
the type determined by the @fa<subtype_mark>. The operand shall have the type
determined by the @fa<subtype_mark>, or a universal type that covers it.

This is goofy, because we're giving the rule twice, with the second more
restrictive that the first. But maybe it is better??

(Note that the second rule cannot be a legality rule without introducing
ambiguity where there currently is none.)

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

From: Robert A Duff
Sent: Friday, July 25, 2003  7:43 PM

> The expected type of the @i<operand> (the @fa<expression> or @fa<aggregate>)
> is the type determined by the @fa<subtype_mark>. The operand shall have the
> type determined by the @fa<subtype_mark>, or a universal type that covers
> it.
>
> This is goofy, because we're giving the rule twice, with the second more
> restrictive that the first. But maybe it is better??

Seems better to me.  Maybe the goofiness can be attenuated by starting
the second sentence with "Furthermore, ".

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

From: Gary Dismukes
Sent: Friday, July 25, 2003  8:02 PM

>     type T1 is record ... end record;
>     type Acc_1 is access all record;
>     type Acc_2 is access all record;

(Randy, if that's text from the AI then be sure to correct
the access types to say "all T1" rather than "all record".:)

> An alternative would be to replace 4.7(3) by:
>
> The expected type of the @i<operand> (the @fa<expression> or @fa<aggregate>)
> is the type determined by the @fa<subtype_mark>. The operand shall have the
> type determined by the @fa<subtype_mark>, or a universal type that covers
> it.
>
> This is goofy, because we're giving the rule twice, with the second more
> restrictive that the first. But maybe it is better??

It seems preferable if the fix can be applied in 4.7(3).  However,
I'm unclear on how this avoids triggering the 8.6(22-25) expected
type rules.  It seems like you're just creating a contradiction
between this new rule and the 8.6 rules, but maybe I'm missing
a subtlety of the wording that avoids invoking the type resolution
rules.

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

From: Randy Brukardt
Sent: Friday, July 25, 2003  8:24 PM

That's why I thought it was goofy.

OTOH, Bob's suggestion of "Furthermore, " helps. We could even go so far as
"Notwithstanding", but that seems like overkill:

The expected type of the @i<operand> (the @fa<expression> or @fa<aggregate>) is
the type determined by the @fa<subtype_mark>. Furthermore, notwithstanding what
this International Standard says elsewhere, the operand shall have the type
determined by the @fa<subtype_mark>, or a universal type that covers it.

That does eliminate all ambiguity, though. Maybe that IS the solution; it's not
as goofy as the first one.

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

From: Tucker Taft
Sent: Sunday, November 16, 2003  8:31 AM

I offered to come up with better wording to fix the
problem that certain contexts do not specify an expected
type.  These contexts generally indicate that something
"shall resolve" to a particular type, and in some cases
allow a universal type that covers it.

We avoided the "expected type" terminology to bypass the
rules in paragraph 8.6(21-25) which are looser than
we would like.  However, this creates problems with the
legality rule in 8.6(27) which seems to require that an
expected type be provided by all contexts.

This rule is (currently) relevant to null, character, and string
literals, to allocators, and to '[Unchecked_]Acccess (any others?).

Here is the current wording for 8.6(27):

  When the expected type for a construct is required to be
  a *single* type in a given class, the type expected for
  the construct shall be determinable solely from the context
  in which the construct appears, excluding the construct itself,
  but using the requirement that it be in the given class; the type
  of the construct is then this single expected type.  Furthermore,
  the context shall not be one that expects any type in some class
  that contains types of the given class; in particular, the construct
  shall not be the operand of a type_conversion.

The second sentence seems OK as is.  The first (long ;-) sentence is
the problem, as it uses the term "expected" three times, and at least
two of them are problematic.

Here is a possible alternative for this first sentence:

 When a construct is one that requires that its expected type be
 a *single* type in a given class, the type of the construct shall
 be determinable solely from the context in which the construct
 appears, excluding the construct itself, but using the requirement
 that it be in the given class.

That seems to solve the problem in my view, in that it only mentions
"expected type" as part of identifying the case we are talking about,
but doesn't require that the context actually *provide* such an expected
type.  Note that I have dropped the trailing phrase "the type of the construct
is then this single expected type," which seems unnecessary with
this new wording.  The second sentence (which should remain) rules out cases
where any type in a class is expected, which might require overload
resolution to deal with cases where there just happens to be only
one such type in scope.

I'll keep working if others don't like the above rewording, but it
seems sufficient to me...

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

From: Tucker Taft
Sent: Sunday, November 16, 2003  8:38 AM

> ...
> This rule is (currently) relevant to null, character, and string
> literals, to allocators, and to '[Unchecked_]Acccess (any others?).

I forgot aggregates.

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

From: Robert Dewar
Sent: Sunday, November 16, 2003  8:47 AM

too bad someone did not forget aggregates when designing the language in
the first place :-) :-)

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

From: Robert I. Eachus
Sent: Sunday, November 16, 2003  10:13 AM

As I remember it from my compiler days, aggregates as parameters weren't
too bad, it was aggregate assignment that was a blinding headache.  I
just mention it because we are running into exactly the same mess in the
other thread.  Sometimes the aggregate takes its constraint from the
target, and sometimes from the aggregate itself, and the compiler
front-end may have to do a lot of work before it knows which case it is
dealing with.

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

From: Randy Brukardt
Sent: Monday, November 24, 2003  8:46 PM

Yes, I think this works. Thanks for the effort.

BTW, in addition to qualified expressions, object renaming uses the "shall
resolve to" wording. Prefix calls (AI-252 and 4.1.3) also do, but those are
restricted to names, so they never trigger this rule.

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


Questions? Ask the ACAA Technical Agent