!standard 12.05.01 (21) 00-07-13 AI95-00202/05 !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 !qualifier Error !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); -- [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: Calls S [5] in instance I? (No.) end G; package P2 is type R2 is new R1; -- implicit: procedure S (x : R2); -- [4] procedure S (x : out R2); -- [5] Overriding with mode out end P2; package P3 is type R3 is new P2.R2; -- implicit: procedure S (x : R3); -- [6] procedure S (x : R3); -- [7] 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 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. The rule of 12.5.1(21) is amended 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 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 problem is fixed 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) @drepl 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. @dby 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 CC51008.A was created to check the example given here has the correct behavior. (Test, 8-0-0, ARG Letter Ballot, February 2001). !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 ****************************************************************