Skip to content

Commit

Permalink
Adapt resolve_names_from_closest_entry_point to use own xref_initial_…
Browse files Browse the repository at this point in the history
…env.
  • Loading branch information
Roldak committed Jun 27, 2024
1 parent eb13bf2 commit b633e98
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 66 deletions.
100 changes: 34 additions & 66 deletions ada/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1115,100 +1115,68 @@ def resolve_names():
origin.bind(Self.origin_node, Entity.resolve_names_internal(False))
)

@langkit_property(return_type=T.LexicalEnv)
def resolve_names_from_closest_entry_point_impl():
@langkit_property(return_type=Bool)
def resolve_names_from_closest_entry_point():
"""
Implementation helper for ``resolve_names_from_closest_entry_point``.
Instead of returning a Boolean, it returns a LexicalEnv, which is
either None (indicating that resolution failed), or contains the
lexical environment which the children of that node should bind when
resolving their own names. This allows propagating the initial env
we got from ``Entity.xref_initial_env`` on the closest xref entry
point.
Resolve names from the closest entry point up to this node. Note that
unlike ``resolve_names``, this will *not* trigger resolution of every
node with stop_resolution that lie in the sub-tree formed by the
closest entry point. It will only resolve those that are in the path to
resolving Self. Consider for example the following entry point:

.. code::

R := (A, B);

Since aggregate association nodes have ``stop_resolution`` set to True,
calling ``resolve_names_from_closest_entry_point`` on ``B`` will
resolve nodes ``R`` and ``B`` but not ``A``, because ``A`` does not lie
on the path to ``B``.

This can be useful for resolving aggregates of variant records, because
resolution of a component association can safely call the resolution
of a discriminant association without triggering an infinite recursion,
as both are on different "paths".
"""
return If(
# This is the closest entry point: resolve its names and return
# its `xref_initial_env` if resolution succeeded, so that children
# will be able to use it to resolve their own names.
# This is the closest entry point: resolve its names and stop the
# recursion.
Entity.xref_entry_point,
env.bind(
Entity.xref_initial_env,
origin.bind(
Self.origin_node,
entry_point.bind(
Self,
If(Entity.resolve_own_names(False),
env,
No(LexicalEnv))
Entity.resolve_own_names(False)
)
)
),

Let(
# Recurse in order to resolve names from the closest entry
# point: `res` will contain the environment to use if we need
# to resolve names inside Self, or None if resolution failed.
lambda
res=Entity.parent
._.resolve_names_from_closest_entry_point_impl:

env.bind(
res,
# Otherwise, recurse on the parent
Entity.parent._.resolve_names_from_closest_entry_point.then(
lambda _: env.bind(
Entity.xref_initial_env,
origin.bind(
Self.origin_node,
Cond(
# Resolution failed for the parent, so return None
# as well.
res == No(T.LexicalEnv),
res,

If(
# Resolution succeeded for the parent and this is a
# stop resolution, so re-use the parent environment
# to resolve Self's names.
# stop resolution, so resolve own names as well.
Entity.xref_stop_resolution,
entry_point.bind(
Self,
If(Entity.resolve_own_names(False),
res,
No(LexicalEnv))
Entity.resolve_own_names(False)
),

# Resolution succeeded but there is nothing to do
# on that particular node: return the parent
# environment, so that deeper children can use it.
res
# Resolution succeeded and there is nothing to do
# on that particular node: return successfully.
True
)
)
)
)
)

@langkit_property(return_type=Bool)
def resolve_names_from_closest_entry_point():
"""
Resolve names from the closest entry point up to this node. Note that
unlike ``resolve_names``, this will *not* trigger resolution of every
node with stop_resolution that lie in the sub-tree formed by the
closest entry point. It will only resolve those that are in the path to
resolving Self. Consider for example the following entry point:

.. code::

R := (A, B);

Since aggregate association nodes have ``stop_resolution`` set to True,
calling ``resolve_names_from_closest_entry_point`` on ``B`` will
resolve nodes ``R`` and ``B`` but not ``A``, because ``A`` does not lie
on the path to ``B``.

This can be useful for resolving aggregates of variant records, because
resolution of a component association can safely call the resolution
of a discriminant association without triggering an infinite recursion,
as both are on different "paths".
"""
result = Var(Entity.resolve_names_from_closest_entry_point_impl)
return result != No(LexicalEnv)

@langkit_property(return_type=T.SolverDiagnostic.array, external=True,
call_memoizable=True, uses_entity_info=True,
uses_envs=True)
Expand Down
23 changes: 23 additions & 0 deletions testsuite/tests/name_resolution/declare_expr_aggregate_2/test.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma Ada_2022;

procedure Test is
type A is array (Natural range 0 .. 1) of Integer;

function F return A is
(declare
I : constant Integer := 0;
J : constant Integer := 1;
begin (I, J));
--% node.findall(lal.AggregateAssoc)[0].f_r_expr.p_referenced_decl()

type B is array (Natural range 0 .. 1) of A;
K : Integer := 3;

function H return B is
(declare
K : constant Integer := 2;
begin (B'First => (K, K), B'Last => (K, K)));
--% node.findall(lal.AggregateAssoc)[-1].f_r_expr.p_referenced_decl()
begin
null;
end;
11 changes: 11 additions & 0 deletions testsuite/tests/name_resolution/declare_expr_aggregate_2/test.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Working on node <ExprFunction ["F"] test.adb:6:4-10:21>
=======================================================

Eval 'node.findall(lal.AggregateAssoc)[0].f_r_expr.p_referenced_decl()'
Result: <ObjectDecl ["I"] test.adb:8:9-8:35>

Working on node <ExprFunction ["H"] test.adb:16:4-19:52>
========================================================

Eval 'node.findall(lal.AggregateAssoc)[-1].f_r_expr.p_referenced_decl()'
Result: <ObjectDecl ["K"] test.adb:18:9-18:35>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
driver: inline-playground
input_sources: [test.adb]

0 comments on commit b633e98

Please sign in to comment.