Skip to content

Commit

Permalink
Optimize implementation of the get_primitives property.
Browse files Browse the repository at this point in the history
Note that this has the side effects or returning primitives in
alphabetical order, whereas the previous ordering was related to
source ordering.
  • Loading branch information
Roldak committed Jul 30, 2024
1 parent 19e5256 commit 6e09d80
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 71 deletions.
134 changes: 73 additions & 61 deletions ada/nodes.lkt
Original file line number Diff line number Diff line change
Expand Up @@ -5227,71 +5227,83 @@ class BaseTypeDecl: BasicDecl {
|" defined on this type. Predefined operators are included in the result
|" iff ``include_predefined_operators`` is True. It defaults to False.
@exported
fun get_primitives(only_inherited: Bool = false, include_predefined_operators: Bool = false): Array[Entity[BasicDecl]] = {
val prim_env = if only_inherited then self.parent_primitives_env() else self.primitives_env();
val all_prims = prim_env.get(null[Symbol]).map((t) => t.as[BasicDecl]);
val bds = if include_predefined_operators then all_prims else all_prims.filter((p) => not p is SyntheticSubpDecl);

# Make sure to return only one instance of each primitive: the most
# "overriding" one.
bds.filter(
(a, i) => {
val a_spec = a.subp_spec_or_null();
val a_prim = a.info.md.primitive.as_bare_entity.as[BaseTypeDecl];
fun get_primitives(
only_inherited: Bool = false,
include_predefined_operators: Bool = false
): Array[Entity[BasicDecl]] = {
val prim_env = if only_inherited then
self.parent_primitives_env()
else
self.primitives_env();

bds.all(
(b, j) => {
val b_prim = b.info.md.primitive.as[BaseTypeDecl];
# First gather the set of names that primitives of this type can have
val all_prim_names = prim_env.get(null[Symbol]).map(
(t) => t.as[BasicDecl].defining_name().name_symbol()
).unique();

(
# Note that we don't want to use `match_name=True` in the
# call to `match_signature` below because it also compares
# the name of the parameters which we don't want to take
# into account here. Therefore, we first compare the names
# of the subprogram separately.
not a.defining_name().node.matches(b.defining_name().node)
) or (
# If two primitives have the same signature...
{
bind origin = b.origin_node();
# Next, for each of these names, we only want to keep the
# "most overriding" ones.
all_prim_names.mapcat((name) => {
val all_prims = prim_env.get(name).map((t) => t.as[BasicDecl]);
val bds = if include_predefined_operators then
all_prims
else
all_prims.filter((p) => not p is SyntheticSubpDecl);

not a_spec.match_signature(
b.subp_spec_or_null(), match_name=false, use_entity_info=true
)
}
) or {
val b_prim_ent = b_prim.as_bare_entity;

# Test if the type of the first primitive (a) derives
# from the type of the second primitive (b)...
if a_prim.has_base_type(b_prim_ent.node) then (
# Case a derives from b...
# If b also derives from a, it means the types are
# equal: both primitives are in fact the same
# subprogram, but the first one is the declaration and
# the second one is the body. In that case we decide to
# keep the body.
# Else if b does not derive from a, it means the
# primitive on a overrides the primitive on b, so
# return True.
i >= j or not b_prim_ent.has_base_type(a_prim.node)
) else (
# Case a does *not* derive from b...
# If b also does not derive from a, the two base types
# are unrelated, it means that the primitives are
# merged in a single one (remember their signature
# match). We keep the one that is inherited first with
# respect to the list of parents.
# But if b derives from a, we return False as we don't
# want to keep this primitive: we will keep the most
# inherited one (defined on b) later instead.
i <= j and not b_prim_ent.has_base_type(a_prim.node)
)
}
bds.filter((a, i) => {
val a_spec = a.subp_spec_or_null();
val a_prim =
a.info.md.primitive.as_bare_entity.as[BaseTypeDecl];

# Only keep primitive a if it is the "most overriding" one.
# So, the logic below checks that there isn't a primitive b
# that overrides it.
not bds.any((b, j) => {
val b_prim = b.info.md.primitive.as[BaseTypeDecl];

(i != j) and {
# If two primitives have the same signature...
bind origin = b.origin_node();

a_spec.match_signature(
b.subp_spec_or_null(),
match_name=false,
use_entity_info=true
)
} and {
val b_prim_ent = b_prim.as_bare_entity;

# Test if the type of the first primitive (a) derives
# from the type of the second primitive (b)...
if a_prim.has_base_type(b_prim_ent.node) then (
# Case a derives from b...
# If b also derives from a, it means the types are
# equal: both primitives are in fact the same
# subprogram, but the first one is the declaration
# and the second one is the body. In that case we
# decide to keep the body.
# Else if b does not derive from a, it means the
# primitive on a overrides the primitive on b, so
# return False.
i < j and b_prim_ent.has_base_type(a_prim.node)
) else (
# Case a does *not* derive from b...
# If b also does not derive from a, the two base
# types are unrelated, it means that the primitives
# are merged in a single one (remember their
# signature match). We keep the one that is
# inherited first with respect to the list of
# parents.
# But if b derives from a, we return True as we
# don't want to keep this primitive: we will keep
# the most inherited one (defined on b) later
# instead.
i > j or b_prim_ent.has_base_type(a_prim.node)
)
}
)
}
)
})
})
})
}

|" Return whether this type is an array type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Working on node <ConcreteTypeDecl ["Child"] test.adb:16:7-16:52>
================================================================

Eval 'node.p_get_primitives()'
Result: [<SubpDecl ["Get2"] test.adb:6:7-6:49>, <SubpDecl ["Get1"] test.adb:19:7-19:59>]
Result: [<SubpDecl ["Get1"] test.adb:19:7-19:59>, <SubpDecl ["Get2"] test.adb:6:7-6:49>]
4 changes: 2 additions & 2 deletions testsuite/tests/properties/inherited_primitives/test.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ Primitives inherited by <ConcreteTypeDecl ["U"] test.adb:10:7-10:42>:
<ExprFunction ["F"] test.adb:5:7-5:42>
<NullSubpDecl ["G"] test.adb:6:7-6:35>
Primitives inherited by <ConcreteTypeDecl ["U"] test.adb:14:7-14:42>:
<NullSubpDecl ["G"] test.adb:6:7-6:35>
<ExprFunction ["F"] test.adb:16:7-16:53>
<NullSubpDecl ["G"] test.adb:6:7-6:35>
Primitives inherited by <ConcreteTypeDecl ["U"] test.adb:32:7-32:42>:
<ExprFunction ["F"] test.adb:16:7-16:53>
<NullSubpDecl ["G"] test.adb:6:7-6:35>
Expand All @@ -14,6 +14,6 @@ Primitives inherited by <ConcreteTypeDecl ["U"] test.adb:36:7-36:50>:
<NullSubpDecl ["B"] test.adb:26:7-26:35>
Primitives inherited by <ConcreteTypeDecl ["U"] test.adb:52:7-52:60>:
<NullSubpDecl ["A"] test.adb:42:7-42:35>
<NullSubpDecl ["C"] test.adb:46:7-46:35>
<NullSubpDecl ["B"] test.adb:53:7-53:35>
<NullSubpDecl ["C"] test.adb:46:7-46:35>
Done
12 changes: 6 additions & 6 deletions testsuite/tests/properties/inherited_primitives_2/test.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ Working on node <ConcreteTypeDecl ["D"] pkg-der.adb:4:4-4:37>
=============================================================

Eval 'node.p_get_primitives()'
Result: [<SubpDecl ["Priv"] pkg.ads:11:4-11:41>,
<NullSubpDecl ["Foo"] pkg-der.adb:8:4-8:34>]
Result: [<NullSubpDecl ["Foo"] pkg-der.adb:8:4-8:34>,
<SubpDecl ["Priv"] pkg.ads:11:4-11:41>]

Working on node <ConcreteTypeDecl ["U"] pkg-der.ads:2:4-2:29>
=============================================================

Eval 'node.p_get_primitives()'
Result: [<SubpDecl ["Foo"] pkg-der.ads:6:4-6:26>,
<NullSubpDecl ["Bar"] pkg-der.ads:12:4-12:34>]
Result: [<NullSubpDecl ["Bar"] pkg-der.ads:12:4-12:34>,
<SubpDecl ["Foo"] pkg-der.ads:6:4-6:26>]

Working on node <ConcreteTypeDecl ["U"] pkg-der.ads:9:4-9:37>
=============================================================

Eval 'node.p_get_primitives()'
Result: [<SubpDecl ["Priv"] pkg.ads:11:4-11:41>,
<SubpDecl ["Foo"] pkg-der.ads:6:4-6:26>,
Result: [<SubpDecl ["Foo"] pkg-der.ads:6:4-6:26>,
<SubpDecl ["Priv"] pkg.ads:11:4-11:41>,
<NullSubpDecl ["Bar"] pkg-der.ads:12:4-12:34>]

Working on node <ConcreteTypeDecl ["T"] pkg.ads:2:4-2:38>
Expand Down
2 changes: 1 addition & 1 deletion testsuite/tests/properties/is_inherited_primitive/test.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
== test.adb ==
For <ConcreteTypeDecl ["Parent"] test.adb:3:7-3:41>, <SubpDecl ["Get1"] test.adb:5:7-5:49> is not inherited
For <ConcreteTypeDecl ["Parent"] test.adb:3:7-3:41>, <SubpDecl ["Get2"] test.adb:6:7-6:49> is not inherited
For <ConcreteTypeDecl ["Child"] test.adb:16:7-16:52>, <SubpDecl ["Get2"] test.adb:6:7-6:49> is inherited
For <ConcreteTypeDecl ["Child"] test.adb:16:7-16:52>, <SubpDecl ["Get1"] test.adb:18:7-18:59> is not inherited
For <ConcreteTypeDecl ["Child"] test.adb:16:7-16:52>, <SubpDecl ["Get2"] test.adb:6:7-6:49> is inherited

Done

0 comments on commit 6e09d80

Please sign in to comment.