Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ForeverStackStore #3251

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ GRS_OBJS = \
rust/rust-ast-resolve-path.o \
rust/rust-ast-resolve-stmt.o \
rust/rust-ast-resolve-struct-expr-field.o \
rust/rust-forever-stack.o \
rust/rust-hir-type-check.o \
rust/rust-privacy-check.o \
rust/rust-privacy-ctx.o \
Expand Down
318 changes: 318 additions & 0 deletions gcc/rust/resolve/rust-forever-stack.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
// Copyright (C) 2024 Free Software Foundation, Inc.

// This file is part of GCC.

// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.

// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.

// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.

#include "expected.h"
#include "rust-ast.h"
#include "rust-diagnostics.h"
#include "rust-forever-stack.h"
#include "rust-rib.h"
#include "optional.h"

namespace Rust {
namespace Resolver2_0 {

bool
ForeverStackStore::Node::is_root () const
{
return !parent.has_value ();
}

bool
ForeverStackStore::Node::is_leaf () const
{
return children.empty ();
}

NodeId
ForeverStackStore::Node::get_id () const
{
return id;
}

ForeverStackStore::Node &
ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path,
Rib::Kind kind)
{
auto res = children.insert ({Link (id, path), Node (kind, id, *this)});

rust_debug ("inserting link: Link(%d [%s]): existed? %s", id,
path.has_value () ? path.value ().as_string ().c_str ()
: "<anon>",
!res.second ? "yes" : "no");

// sanity check on rib kind
// pick the value rib, since all ribs should have the same kind anyways
rust_assert (res.second || res.first->second.value_rib.kind == kind);

// verify, if we're using an existing node, our paths don't contradict
if (!res.second && path.has_value ())
{
auto other_path = res.first->first.path;
rust_assert (!other_path.has_value ()
|| other_path.value ().as_string ()
== path.value ().as_string ());
}

return res.first->second;
}

tl::optional<ForeverStackStore::Node &>
ForeverStackStore::Node::get_child (const Identifier &path)
{
for (auto &ent : children)
{
if (ent.first.path.has_value ()
&& ent.first.path->as_string () == path.as_string ())
return ent.second;
}
return tl::nullopt;
}

tl::optional<const ForeverStackStore::Node &>
ForeverStackStore::Node::get_child (const Identifier &path) const
{
for (auto &ent : children)
{
if (ent.first.path.has_value ()
&& ent.first.path->as_string () == path.as_string ())
return ent.second;
}
return tl::nullopt;
}

tl::optional<ForeverStackStore::Node &>
ForeverStackStore::Node::get_parent ()
{
return parent;
}

tl::optional<const ForeverStackStore::Node &>
ForeverStackStore::Node::get_parent () const
{
if (parent)
return *parent;
return tl::nullopt;
}

tl::optional<const Identifier &>
ForeverStackStore::Node::get_parent_path () const
{
if (parent.has_value ())
for (auto &ent : parent->children)
if (ent.first.id == id && ent.first.path.has_value ())
return ent.first.path.value ();
return tl::nullopt;
}

Rib &
ForeverStackStore::Node::get_rib (Namespace ns)
{
switch (ns)
{
case Namespace::Values:
return value_rib;
case Namespace::Types:
return type_rib;
case Namespace::Labels:
return label_rib;
case Namespace::Macros:
return macro_rib;
default:
rust_unreachable ();
}
}

const Rib &
ForeverStackStore::Node::get_rib (Namespace ns) const
{
switch (ns)
{
case Namespace::Values:
return value_rib;
case Namespace::Types:
return type_rib;
case Namespace::Labels:
return label_rib;
case Namespace::Macros:
return macro_rib;
default:
rust_unreachable ();
}
}

tl::expected<NodeId, DuplicateNameError>
ForeverStackStore::Node::insert (const Identifier &name, NodeId node,
Namespace ns)
{
// So what do we do here - if the Rib has already been pushed in an earlier
// pass, we might end up in a situation where it is okay to re-add new names.
// Do we just ignore that here? Do we keep track of if the Rib is new or not?
// should our cursor have info on the current node like "is it newly pushed"?
return get_rib (ns).insert (name.as_string (),
Rib::Definition::NonShadowable (node));
}

tl::expected<NodeId, DuplicateNameError>
ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node,
Namespace ns)
{
return get_rib (ns).insert (name.as_string (),
Rib::Definition::Shadowable (node));
}

tl::expected<NodeId, DuplicateNameError>
ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node,
Namespace ns)
{
return get_rib (ns).insert (name.as_string (),
Rib::Definition::Globbed (node));
}

void
ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda)
{
for (Node *tmp = this; lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
tmp = &tmp->parent.value ())
;
}

void
ForeverStackStore::Node::reverse_iter (
std::function<KeepGoing (const Node &)> lambda) const
{
for (const Node *tmp = this;
lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
tmp = &tmp->parent.value ())
;
}

void
ForeverStackStore::Node::child_iter (
std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)>
lambda)
{
for (auto &ent : children)
{
tl::optional<const Identifier &> path;
if (ent.first.path.has_value ())
path = ent.first.path.value ();
auto keep_going = lambda (ent.first.id, path, ent.second);
if (keep_going == KeepGoing::No)
return;
}
}

void
ForeverStackStore::Node::child_iter (
std::function<KeepGoing (NodeId, tl::optional<const Identifier &>,
const Node &)>
lambda) const
{
for (auto &ent : children)
{
tl::optional<const Identifier &> path;
if (ent.first.path.has_value ())
path = ent.first.path.value ();
auto keep_going = lambda (ent.first.id, path, ent.second);
if (keep_going == KeepGoing::No)
return;
}
}

ForeverStackStore::Node &
ForeverStackStore::Node::find_closest_module ()
{
// get kind of value_rib
// but all ribs should share the same kind anyways
if (value_rib.kind == Rib::Kind::Module || !parent.has_value ())
return *this;
else
return parent->find_closest_module ();
}

const ForeverStackStore::Node &
ForeverStackStore::Node::find_closest_module () const
{
// get kind of value_rib
// but all ribs should share the same kind anyways
if (value_rib.kind != Rib::Kind::Module || !parent.has_value ())
return *this;
else
return parent->find_closest_module ();
}

tl::optional<ForeverStackStore::Node &>
ForeverStackStore::Node::dfs_node (NodeId to_find)
{
if (id == to_find)
return *this;

for (auto &child : children)
{
auto candidate = child.second.dfs_node (to_find);

if (candidate.has_value ())
return candidate;
}

return tl::nullopt;
}

tl::optional<const ForeverStackStore::Node &>
ForeverStackStore::Node::dfs_node (NodeId to_find) const
{
if (id == to_find)
return *this;

for (auto &child : children)
{
auto candidate = child.second.dfs_node (to_find);

if (candidate.has_value ())
return candidate;
}

return tl::nullopt;
}

ForeverStackStore::Node &
ForeverStackStore::get_root ()
{
return root;
}

const ForeverStackStore::Node &
ForeverStackStore::get_root () const
{
return root;
}

tl::optional<ForeverStackStore::Node &>
ForeverStackStore::get_node (NodeId node_id)
{
return root.dfs_node (node_id);
}

tl::optional<const ForeverStackStore::Node &>
ForeverStackStore::get_node (NodeId node_id) const
{
return root.dfs_node (node_id);
}

} // namespace Resolver2_0
} // namespace Rust
Loading
Loading