Version 1.6 of ais/ai-00202.txt
!standard 12.05.01 (21) 99-07-28 AI95-00202/04
!class binding interpretation 98-03-27
!status Corrigendum 2000 99-07-28
!status WG9 approved 99-06-12
!status ARG Approved (with changes) 9-0-1 99-03-25
!status work item 98-10-02
!status received 98-03-27
!priority Medium
!difficulty Hard
!subject Primitives of formal type derived from another formal type
!summary
In an instance of a generic unit having a formal derived type whose ancestor
is itself a formal type, the copies of the implicit subprogram declarations
of the formal derived type declare views of the corresponding copies of the
primitive subprograms of the formal ancestor type.
!question
In an instance of a generic with a formal derived type whose ancestor type
is another formal type, the rules regarding the meanings of the implicit
declarations for the formal derived type produce a peculiar result.
Consider the following example:
package P1 is
type R1 is record ... end record;
procedure S (x : R1); --
end P1;
use P1;
generic
type F2 is new R1;
--
type F3 is new F2;
--
procedure G (o2 : F2; o3 : F3);
procedure G (o2 : F2; o3 : F3) is
begin
S(o2);
S(o3); --
end G;
package P2 is
type R2 is new R1;
--
procedure S (x : out R2); --
end P2;
package P3 is
type R3 is new P2.R2;
--
procedure S (x : R3); --
end P3;
procedure I is new G (P2.R2, P3.R3);
In the instance I, the implicit declarations of S which operate on F2 and F3,
respectively, are the corresponding primitive subprograms of the ancestor
types of each type, as stated in RM95 12.5.1(21). The ancestor type of F2 is
R1, so the implicit declaration of S that operates on F2 [2] is a view of the
corresponding primitive subprogram of R1 [1].
The ancestor type of F3 is the type of the subtype denoted by the name F2 in
the instance, which is R2. So, the implicit declaration of S that operates
on F3 [3] is a view of the corresponding primitive subprogram of R2 [5].
But, the annotation in AARM 12.5.1(21.a) indicates that the reason the
primitives of a formal derived type in an instance are views of its
ancestor's primitives is because the primitives of its actual type might not
be subtype conformant with those of its ancestor type. This intention could
be violated if the primitive S [3] is a view of the primitive S [5].
Is it the intent that the primitive S [3] should declare a view of S [1]?
(Yes.)
In general, when the ancestor type of a formal derived type is itself
another formal type, then within an instance does the derived type
acquire the primitive operations of the formal ancestor type or the
primitive operations of the ancestor type's corresponding actual type?
(The primitive operations of the formal ancestor.)
!recommendation
The copies of the implicitly declared primitive subprograms of a formal
derived type in an instance are defined to be views of the ancestor type's
corresponding operations (12.5.1(21)). In the case of a formal type whose
ancestor is another formal type of the same generic unit, this results
in the undesirable semantics that in an instance, the copies of the first
formal type's implicitly declared operations are views of the corresponding
operations of the ancestor type's actual type.
It is essential to ensure that such copied implicit operations are always
views of some ancestor known at the point of the generic formal type's
declaration, since using the operations of the formal ancestor's actual
type can lead to inconsistencies because the operations of an actual
(untagged) type may not be subtype conformant with those of the formal type.
This AI amends the rule of 12.5.1(21) to correct this problem. The copies
of a formal derived type's operations in an instance are defined to be
views of the corresponding copies of the primitive operations of the
formal type's ancestor when the ancestor is a formal type, rather than
simply those of "the ancestor type" (which in an instance would denote
the actual type associated with the formal type's ancestor).
Note that in the case where the formal ancestor type is a formal derived
type, the copied operations of the ancestor type in the instance are
themselves views of operations coming from the ancestor type's own ancestor
(so the new rule applies transitively for arbitrary levels of derivation
from formal derived types).
!wording
The second sentence of 12.5.1(21) should be corrected to cover the case
where the formal derived type has a formal ancestor type declared in
the same generic formal part. The copied operations of the formal
derived type must be defined to declare views of the corresponding
copied operations of the ancestor.
!discussion
Paragraph 12.5.1(21) defines the implicit operations that are declared
for a formal derived type, as well as the meaning of the copies of those
implicit operations declared within an instance. The second sentence
states:
In an instance, the copy of such an implicit declaration declares
a view of the corresponding primitive subprogram of the ancestor,
even if this primitive has been overridden for the actual type.
However, in the instance of a generic unit with formal derived type T2
whose ancestor type is itself a formal derived type T1, the phrase
"of the ancestor" must be interpreted as referring to the actual
type A1 associated with the formal ancestor T1. This is because
in the instance, the ancestor type of the copy of T2 is a view of the
actual type A1 associated with T1. This is the normal interpretation
of copies of declarations within instances as defined by the static
semantics in 12.3(13-16). But that leads to the conclusion that the
view defined in 12.5.1(21) denotes the corresponding primitive
subprogram of the ancestor's actual type.
As shown in the example of the !question section, this can result
in inconsistent views of a formal type's primitive operations,
since the formal view of a primitive may not be subtype conformant
with the view in an instance. For example, modes of parameters may
differ between the formal and actual views of an subprogram, leading
to undefined semantics for the copied version of a call to such
a subprogram from within an instance. This would essentially
result in a generic contract model violation in the body of the
instance.
The Ramification in AARM-12.5.1(21.a) makes the intent behind 12.5.1(21)
clear, explaining how in the case of untagged types the rule ensures that
the operations of the type in an instance are those of the ancestor rather
than those of the actual type, which may not be subtype conformant.
However the formulation of the rule does not account for cases where the
ancestor is a formal type itself, whose operations may not be subtype
conformant with those of a corresponding actual type in an instance.
This AI fixes this problem by specifying that, in an instance, the
implicit declaration of a primitive subprogram of a formal derived
type with a formal ancestor declares a view of the corresponding
copied operation of the ancestor.
If the ancestor is a nonderived formal type, then the copied operations
of the ancestor declare views of the predefined operators of the ancestor's
corresponding actual type.
In the case where the ancestor is itself a formal derived type, then
the copied operations of the ancestor will themselves be views of
operations coming from the ancestor type's own ancestor, so the rule
applies transitively for arbitrary levels of derivation from formal
derived types.
!corrigendum 12.05.01(21)
Replace the paragraph:
For a formal derived type, the predefined operators and inherited
user-defined subprograms are determined by the ancestor type, and are
implicitly declared at the earliest place, if any, within the immediate scope
of the formal type, where the corresponding primitive subprogram of the
ancestor is visible (see 7.3.1). In an instance, the copy of such an
implicit declaration declares a view of the corresponding primitive
subprogram of the ancestor, even if this primitive has been overridden for
the actual type. In the case of a formal private extension, however, the tag
of the formal type is that of the actual type, so if the tag in a call is
statically determined to be that of the formal type, the body executed will
be that corresponding to the actual type.
by:
For a formal derived type, the predefined operators and inherited user-defined
subprograms are determined by the ancestor type, and are implicitly declared at
the earliest place, if any, within the immediate scope of the formal type, where
the corresponding primitive subprogram of the ancestor is visible (see 7.3.1).
In an instance, the copy of such an implicit declaration declares a view of the
corresponding primitive subprogram of the ancestor of the formal derived type,
even if this primitive has been overridden for the actual type. When the
ancestor of the formal derived type is itself a formal type, the copy of the
implicit declaration declares a view of the corresponding copied operation of
the ancestor. In the case of a formal private extension, however, the tag of the
formal type is that of the actual type, so if the tag in a call is statically
determined to be that of the formal type, the body executed will be that
corresponding to the actual type.
!ACATS test
Create a C-Test that checks the example given here has the correct behavior.
!appendix
!section 12.5.1(21)
!subject Primitives of formal type derived from another formal type
!reference RM95-12.5.1(21)
!reference AARM-12.5.1(21.a)
!from Todd Allen 98-02-27
!keywords generic formal derived type, ancestor subtype, primitive
!reference 1998-15814.a Todd Allen 1998-2-27>>
!discussion
In an instance of a generic where a formal derived type whose ancestor type
is another formal type, the rules regarding the meanings of the implicit
declarations for the formal derived type produce a peculiar result.
Consider the following example:
package P1 is
type R1 is record .. end record;
procedure S (x : R1); -- (1)
end P1;
use P1;
generic
type F2 is new R1;
-- implicit: procedure S (x : F2); -- (2)
type F3 is new F2;
-- implicit: procedure S (x : F3); -- (3)
procedure G (o2 : F2; o3 : F3);
procedure G (o2 : F2; o3 : F3) is
begin
S(o2);
S(o3); -- Peculiar result
end G;
package P2 is
type R2 is new R1;
-- implicit: procedure S (x : R2); -- (4)
procedure S (x : R2); -- (5)
end P2;
use P2;
package P3 is
type R3 is new R2;
-- implicit: procedure S (x : R3); -- (6)
procedure S (x : r3); -- (7)
end P3;
use P3;
procedure I is new G(R2, R3);
In the instance I, the implicit declarations of S which operate on F2 and F3,
respectively are the corresponding primitive subprograms of the ancestor
types of each type, as stated in RM95 12.5.1(21). The ancestor type of F2 is
R1, so the implicit declaration of S that operates on F2 (2) is a view of the
corresponding primitive subprogram of R1 (1).
The ancestor type of F3 is the type of the subtype denoted by the name F2 in
the instance, which is R2. So, the implicit declaration of S that operates
on F3 (3) is a view of the corresponding primitive subprogram of R2 (5).
But, the annotation in AARM 12.5.1(21.a) indicates that the reason the
primitives of a formal derived type in an instance are views of its
ancestor's primitives is because the primitives of its actual type might not
be subtype conformant with those of its ancestor type. This intention could
be violated if the primitive S (3) is a view of the primitive S (5). Our
belief is that intent was that the primitive S (3) should instead declare a
view of S (1).
--
Todd Allen
Concurrent Computer Corporation
Fort Lauderdale, FL 33309
****************************************************************
Questions? Ask the ACAA Technical Agent