Given a generic parent package:
generic
type T(<>) is tagged;
package Parent is
-- Stuff
end Parent;
is there a way in a child package to ensure a type passed into the child as a generic formal is the same type as (or even a descendant of) Parent.T? For example, consider the generic child package:
generic
type T(<>) is new Base with private;
package Parent.Child is
-- stuff
end Parent.Child;
where Base is some base tagged type. You can use the following as a placeholder:
type Base is tagged limited null record;
I'm looking for a way either compile time or runtime to verify inside of Parent.Child that Parent.Child.T is the same as Parent.T (or even if Parent.Child.T is a descendent of Parent.T.
NOTE: I am trying to use the parent child package relationship because it allows Child to see into the private section of Parent.
Naively I tried something runtime based like:
package body Child is
-- other stuff
begin
if Child.T not in Parent.T then
raise Storage_Error with "Invalid type passed to child package";
end if;
end Child;
but that just results in a GNAT error:
premature usage of incomplete type "T"
because Parent.T is incomplete. The intent here is to create an automatic memory management framework that can be used with incomplete types, so the parent package provides the majority of the functionality while the child package can be instantiated later and add functionality that requires the full type information (like construction/deallocation). You could then do declarations like:
type Test is tagged;
package B is new Parent(Test);
type Test is new Base with record
Thing : -- Some type from Parent;
end record;
package M is new B.Child(Test);
Any suggestions on how to verify that Parent.T is the same or a descendant of Parent.Child.T? Compile time versions would be preferred but even runtime checking will work.
CodePudding user response:
What about forcing them to have the same base?
generic
type T (<>) is tagged private;
package Parent is
end Parent;
generic
type T (<>) is new Parent.T with private;
package Parent.Child is
end Parent.Child;
with Parent.Child;
package User is
type Base is tagged null record;
package P is new Parent (T => Base);
-- this is OK
type Extension is new Base with null record;
package PC is new P.Child (T => Extension);
-- this fails
type Wrong is tagged null record;
package PF is new P.Child (T => Wrong);
end User;
The error message (using -gnatl
) is
>>> expect type derived from "T" in instantiation
>>> instantiation abandoned
CodePudding user response:
If you don't need the parent/child relationship of the generics, you can do something like this:
foo.ads
generic
type T(<>) is tagged;
package Foo is
end Foo;
bar.ads
with Foo;
generic
type T(<>) is tagged private;
with package Foo_Instance is new Foo(T); --package parameter
package Bar is
end Bar;
This way, the complete type must exactly match the incomplete type, ie. it cannot be a type extension, thus:
with Foo;
with Bar;
package Baz is
type Base is tagged;
package Base_Foo is new Foo(Base);
type Base is tagged null record;
package Base_Bar is new Bar(Base, Base_Foo);
type Extension is new Base with null record;
package Extension_Bar is new Bar(Extension, Base_Foo); -- fails!
end Baz;