3.10.1 Incomplete Type Declarations
1
There are no particular limitations on the designated
type of an access type. In particular, the type of a component of the
designated type can be another access type, or even the same access type.
This permits mutually dependent and recursive access types. An incomplete_type_declaration
can be used to introduce a type to be used as a designated type, while
deferring its full definition to a subsequent full_type_declaration.
Syntax
2/2
{
AI95-00326-01}
incomplete_type_declaration ::= type defining_identifier [
discriminant_part]
[is tagged];
Static Semantics
2.1/2
{
AI95-00326-01}
{incomplete type}
{incomplete view}
An incomplete_type_declaration
declares an incomplete view of a type and its first subtype; the
first subtype is unconstrained if a discriminant_part
appears. If the incomplete_type_declaration
includes the reserved word tagged, it declares a tagged incomplete
view.{incomplete view (tagged)}
{tagged incomplete
view} An incomplete view of a type is
a limited view of the type (see 7.5).
2.2/2
{
AI95-00326-01}
Given an access type A whose designated
type T is an incomplete view, a dereference of a value of type
A also has this incomplete view except when:
2.3/2
- it occurs within
the immediate scope of the completion of T, or
2.4/2
- it occurs within
the scope of a nonlimited_with_clause that
mentions a library package in whose visible part the completion of T
is declared.
2.5/2
In these cases, the dereference
has the full view of T.
2.a/2
Discussion:
We need the “in whose visible part” rule so that the
second rule doesn't trigger in the body of a package with a with
of a child unit:
2.b/2
package P is
private
type T;
type PtrT is access T;
end P;
2.c/2
private package P.C is
Ptr : PtrT;
end P.C;
2.d/2
with P.C;
package body P is
-- Ptr.all'Size is not legal here, but it is in the scope of a
-- nonlimited_with_clause for P.
type T is ...
-- Ptr.all'Size is legal here.
end P;
2.6/2
{
AI95-00412-01}
Similarly, if a subtype_mark
denotes a subtype_declaration defining a subtype
of an incomplete view T, the subtype_mark
denotes an incomplete view except under the same two circumstances given
above, in which case it denotes the full view of T.
Legality Rules
3
{requires a completion
(incomplete_type_declaration) [partial]} An
incomplete_type_declaration requires a completion,
which shall be a
full_type_declaration. [If
the
incomplete_type_declaration occurs immediately
within either the visible part of a
package_specification
or a
declarative_part, then the
full_type_declaration
shall occur later and immediately within this visible part or
declarative_part.
If the
incomplete_type_declaration occurs
immediately within the private part of a given
package_specification,
then the
full_type_declaration shall occur
later and immediately within either the private part itself, or the
declarative_part
of the corresponding
package_body.]
3.a
Proof: This is implied by the next AARM-only
rule, plus the rules in
3.11.1, “
Completions
of Declarations” which require a completion to appear later
and immediately within the same declarative region.
3.b
To be honest: If the incomplete_type_declaration
occurs immediately within the visible part of a package_specification,
then the full_type_declaration shall occur
immediately within this visible part.
3.c
To be honest: If the implementation supports
it, an incomplete_type_declaration can be
completed by a pragma Import.
4/2
{
AI95-00326-01}
If an incomplete_type_declaration
includes the reserved word tagged, then a full_type_declaration
that completes it shall declare a tagged type. If an
incomplete_type_declaration
has a
known_discriminant_part, then a
full_type_declaration
that completes it shall have a fully conforming (explicit)
known_discriminant_part
(see
6.3.1).
{full
conformance (required)} [If an
incomplete_type_declaration
has no
discriminant_part (or an
unknown_discriminant_part),
then a corresponding
full_type_declaration
is nevertheless allowed to have discriminants, either explicitly, or
inherited via derivation.]
5/2
{
AI95-00326-01}
A The only allowed
uses of a name that denotes an
incomplete
view of a type may be used incomplete_type_declaration
are as follows:
5.a/2
This paragraph
was deleted.Discussion: {
AI95-00326-01}
No need to say "prior to the end of the full_type_declaration"
since the name would not denote the incomplete_type_declaration
after the end of the full_type_declaration.
Also, with child library units, it would not be well defined whether
they come before or after the full_type_declaration
for deferred incomplete types.
6
- as the subtype_mark
in the subtype_indication of an access_to_object_definition;
[the only form of constraint allowed in this
subtype_indication is a discriminant_constraint;]
6.a
Implementation Note: We now allow discriminant_constraints
even if the full type is deferred to the package body. However, there
is no particular implementation burden because we have dropped the concept
of the dependent compatibility check. In other words, we have effectively
repealed AI83-00007.
7/2
- {AI95-00326-01}
{AI95-00412-01}
as the subtype_mark in
the subtype_indication of a subtype_declaration;
the subtype_indication shall not have a null_exclusion
or a constraint; defining
the subtype of a parameter or result of an access_to_subprogram_definition;
7.a/2
This paragraph
was deleted.Reason: {
AI95-00326-01}
This allows, for example, a record to have a component
designating a subprogram that takes that same record type as a parameter.
8/2
8.1/2
{
AI95-00326-01}
If such a name denotes
a tagged incomplete view, it may also be used:
8.2/2
- {AI95-00326-01}
as the subtype_mark
defining the subtype of a parameter in a formal_part;
9/2
- {AI95-00326-01}
as the prefix of an attribute_reference
whose attribute_designator is Class; such
an attribute_reference is similarly
restricted to the uses allowed here; it
denotes a tagged incomplete view when used
in this way, the corresponding full_type_declaration
shall declare a tagged type, and the attribute_reference
shall occur in the same library unit as the incomplete_type_declaration.
9.a/2
This paragraph
was deleted.Reason: {
AI95-00326-01}
This is to prevent children from imposing requirements
on their ancestor library units for deferred incomplete types.
9.1/2
{
AI95-00326-01}
If such a name occurs
within the declaration list containing the completion of the incomplete
view, it may also be used:
9.2/2
- {AI95-00326-01}
as the subtype_mark
defining the subtype of a parameter or result of an access_to_subprogram_definition.
9.a.1/2
Reason: This allows,
for example, a record to have a component designating a subprogram that
takes that same record type as a parameter.
9.3/2
{
AI95-00326-01}
If any of the above uses occurs as part of the
declaration of a primitive subprogram of the incomplete view, and the
declaration occurs immediately within the private part of a package,
then the completion of the incomplete view shall also occur immediately
within the private part; it shall not be deferred to the package body.
9.b/2
Reason: This fixes
a hole in Ada 95 where a dispatching operation with an access parameter
could be declared in a private part and a dispatching call on it could
occur in a child even though there is no visibility on the full type,
requiring access to the controlling tag without access to the representation
of the type.
9.4/2
{
AI95-00326-01}
No other uses of a name
that denotes an incomplete view of a type are allowed.
10/2
{
AI95-00326-01}
A prefix that denotes
an object A dereference (whether implicit
or explicit — see 4.1) shall not
be of an incomplete
view type.
10.a/2
Reason: We used
to disallow all dereferences of an incomplete type. Now we only disallow
such dereferences when used as a prefix. Dereferences
used in other contexts do not pose a problem since normal type matching
will preclude their use except when the full type is “nearby”
as context (for example, as the expected type).
10.b/2
This also disallows prefixes
that are directly of an incomplete view. For instance, a parameter P
can be declared of a tagged incomplete type, but we don't want to allow
P'Size, P'Alignment, or the like, as representation values
aren't known for an incomplete view.
10.c/2
We say “denotes
an object” so that prefixes that directly name an incomplete view
are not covered; the previous rules cover such cases, and we certainly
don't want to ban Incomp'Class.
Static Semantics
11/2
This paragraph was
deleted.{
AI95-00326-01}
{incomplete type}
An incomplete_type_declaration
declares an incomplete type and its first subtype; the first subtype
is unconstrained if a known_discriminant_part
appears.
11.a/2
This paragraph
was deleted.Reason: If an unknown_discriminant_part
or no discriminant_part appears, then the
constrainedness of the first subtype doesn't matter for any other rules
or semantics, so we don't bother defining it. The case with a known_discriminant_part
is the only case in which a constraint could later be given in a subtype_indication
naming the incomplete type.
Dynamic Semantics
12
{elaboration (incomplete_type_declaration)
[partial]} The elaboration of an
incomplete_type_declaration
has no effect.
12.a
Reason: An incomplete type has no real
existence, so it doesn't need to be "created" in the usual
sense we do for other types. It is roughly equivalent to a "forward;"
declaration in Pascal. Private types are different, because they have
a different set of characteristics from their full type.
13
84
{completion
legality [partial]} Within a
declarative_part,
an
incomplete_type_declaration and a corresponding
full_type_declaration cannot be separated
by an intervening body. This is because a type has to be completely defined
before it is frozen, and a body freezes all types declared prior to it
in the same
declarative_part (see
13.14).
Examples
14
Example of a recursive
type:
15
type Cell; -- incomplete type declaration
type Link is access Cell;
16
type Cell is
record
Value : Integer;
Succ : Link;
Pred : Link;
end record;
17
Head : Link := new Cell'(0, null, null);
Next : Link := Head.Succ;
18
Examples of mutually dependent access types:
19/2
{
AI95-00433-01}
type Person(<>); --
incomplete type declaration
type Car
is tagged;; --
incomplete type declaration
20/2
{
AI95-00433-01}
type Person_Name
is access Person;
type Car_Name
is access all Car
'Class;
21/2
{
AI95-00433-01}
type Car
is tagged
record
Number : Integer;
Owner : Person_Name;
end record;
22
type Person(Sex : Gender) is
record
Name : String(1 .. 20);
Birth : Date;
Age : Integer range 0 .. 130;
Vehicle : Car_Name;
case Sex is
when M => Wife : Person_Name(Sex => F);
when F => Husband : Person_Name(Sex => M);
end case;
end record;
23
My_Car, Your_Car, Next_Car : Car_Name :=
new Car; --
see 4.8
George : Person_Name :=
new Person(M);
...
George.Vehicle := Your_Car;
Extensions to Ada 83
23.a
{
extensions to Ada 83}
The
full_type_declaration that completes an
incomplete_type_declaration
may have a
known_discriminant_part even if
the
incomplete_type_declaration does not.
23.b/1
A discriminant_constraint
may be applied to an incomplete type, even if it
its completion is deferred to the package body, because there
is no “dependent compatibility check” required any more.
Of course, the constraint can be specified only if a known_discriminant_part
was given in the incomplete_type_declaration.
As mentioned in the previous paragraph, that is no longer required even
when the full type has discriminants.
Wording Changes from Ada 83
23.c
Dereferences producing
incomplete types were not explicitly disallowed in RM83, though AI83-00039
indicated that it was not strictly necessary since troublesome cases
would result in Constraint_Error at run time, since the access value
would necessarily be null. However, this introduces an undesirable implementation
burden, as illustrated by Example 4 of AI83-00039:
23.d
package Pack is
type Pri is private;
private
type Sep;
type Pri is access Sep;
X : Pri;
end Pack;
23.e
package body Pack is -- Could be separately compiled!
type Sep is ...;
X := new Sep;
end Pack;
23.f
pragma Elaborate(Pack);
private package Pack.Child is
I : Integer := X.all'Size; -- Legal, by AI-00039.
end Pack.Child;
23.g
Generating code for the above example could
be a serious implementation burden, since it would require all aliased
objects to store size dope, and for that dope to be in the same format
for all kinds of types (or some other equivalently inefficient implementation).
On the contrary, most implementations allocate dope differently (or not
at all) for different designated subtypes.
Incompatibilities With Ada 95
23.h/2
{
AI95-00326-01}
{incompatibilities with Ada 95} It
is now illegal to use an incomplete view (type) as the parameter or result
of an access-to-subprogram type unless the incomplete view is completed
in the same declaration list as the use. This was allowed in Ada 95 for
incomplete types where the completion was deferred to the body. By disallowing
this rare use of incomplete views, we can allow the use of incomplete
views in many more places, which is especially valuable for limited views.
23.i/2
{
AI95-00326-01}
It is now illegal to use an incomplete view (type)
in a primitive subprogram of the type unless the incomplete view is completed
in the package specification. This was allowed in Ada 95 for incomplete
types where the completion was deferred to the body (the use would have
to be in an access parameter). This incompatibility was caused by the
fix for the hole noted in Legality Rules above.
Extensions to Ada 95
23.j/2
{
AI95-00326-01}
{extensions to Ada 95} Tagged
incomplete types are new. They are allowed in parameter declarations
as well as the usual places, as tagged types are always by-reference
types (and thus there can be no code generation issue).
23.k/2
{
AI95-00412-01}
A subtype_declaration
can be used to give a new name to an incomplete view of a type. This
is valuable to give shorter names to entities imported with a limited_with_clause.
Wording Changes from Ada 95
23.l/2
{
AI95-00326-01}
The description of incomplete types as incomplete
views is new. Ada 95 defined these as separate types, but neglected
to give any rules for matching them with other types. Luckily, implementers
did the right thing anyway. This change also makes it easier to describe
the meaning of a limited view.