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

Fix rebinding imports #2312

Merged
merged 1 commit into from
Feb 13, 2024
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
179 changes: 86 additions & 93 deletions gcc/rust/resolve/rust-ast-resolve-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -891,92 +891,85 @@ ResolveItem::resolve_extern_item (AST::ExternalItem *item)
}

static void
flatten_glob (const AST::UseTreeGlob &glob,
std::vector<AST::SimplePath> &paths);
flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports);
static void
flatten_rebind (const AST::UseTreeRebind &glob,
std::vector<AST::SimplePath> &paths);
flatten_rebind (const AST::UseTreeRebind &glob, std::vector<Import> &imports);
static void
flatten_list (const AST::UseTreeList &glob,
std::vector<AST::SimplePath> &paths);
flatten_list (const AST::UseTreeList &glob, std::vector<Import> &imports);

static void
flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
flatten (const AST::UseTree *tree, std::vector<Import> &imports)
{
switch (tree->get_kind ())
{
case AST::UseTree::Glob: {
auto glob = static_cast<const AST::UseTreeGlob *> (tree);
flatten_glob (*glob, paths);
flatten_glob (*glob, imports);
break;
}
case AST::UseTree::Rebind: {
auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
flatten_rebind (*rebind, paths);
flatten_rebind (*rebind, imports);
break;
}
case AST::UseTree::List: {
auto list = static_cast<const AST::UseTreeList *> (tree);
flatten_list (*list, paths);
flatten_list (*list, imports);
break;
}
break;
}
}

static void
flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports)
{
if (glob.has_path ())
paths.emplace_back (glob.get_path ());
imports.emplace_back (glob.get_path (), true, std::string ());
}

static void
flatten_rebind (const AST::UseTreeRebind &rebind,
std::vector<AST::SimplePath> &paths)
flatten_rebind (const AST::UseTreeRebind &rebind, std::vector<Import> &imports)
{
auto path = rebind.get_path ();
if (rebind.has_path ())
paths.emplace_back (path);

// FIXME: Do we want to emplace the rebind here as well?
std::string label;
if (rebind.has_identifier ())
{
auto rebind_path = path;
auto new_seg = rebind.get_identifier ();

// Add the identifier as a new path
rebind_path.get_segments ().back ()
= AST::SimplePathSegment (new_seg.as_string (), UNDEF_LOCATION);
label = rebind.get_identifier ().as_string ();
else
label = path.get_final_segment ().as_string ();

paths.emplace_back (rebind_path);
}
imports.emplace_back (path, false, label);
}

static void
flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
flatten_list (const AST::UseTreeList &list, std::vector<Import> &imports)
{
auto prefix = AST::SimplePath::create_empty ();
if (list.has_path ())
prefix = list.get_path ();

for (const auto &tree : list.get_trees ())
{
auto sub_paths = std::vector<AST::SimplePath> ();
flatten (tree.get (), sub_paths);
// append imports to the main list, then modify them in-place
auto start_idx = imports.size ();
flatten (tree.get (), imports);

for (auto &sub_path : sub_paths)
{
auto new_path = prefix;
std::copy (sub_path.get_segments ().begin (),
sub_path.get_segments ().end (),
std::back_inserter (new_path.get_segments ()));

paths.emplace_back (new_path);
}
for (auto import = imports.begin () + start_idx; import != imports.end ();
import++)
import->add_prefix (prefix);
}
}

void
Import::add_prefix (AST::SimplePath prefix)
{
AST::SimplePath old_path (std::move (path));
path = std::move (prefix);
std::move (old_path.get_segments ().begin (), old_path.get_segments ().end (),
std::back_inserter (path.get_segments ()));
}

/**
* Flatten a UseDeclaration's UseTree into multiple simple paths to resolve.
*
Expand All @@ -997,21 +990,21 @@ flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
* Finally in the third case, we want to create two SimplePaths to resolve:
* [some::path::one, some::path::two]
*/
static std::vector<AST::SimplePath>
flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
static std::vector<Import>
flatten_use_dec_to_imports (const AST::UseDeclaration &use_item)
{
auto paths = std::vector<AST::SimplePath> ();
auto imports = std::vector<Import> ();

const auto &tree = use_item.get_tree ();
flatten (tree.get (), paths);
flatten (tree.get (), imports);

return paths;
return imports;
}

void
ResolveItem::visit (AST::UseDeclaration &use_item)
{
std::vector<AST::SimplePath> to_resolve = flatten_use_dec_to_paths (use_item);
std::vector<Import> to_resolve = flatten_use_dec_to_imports (use_item);

// FIXME: I think this does not actually resolve glob use-decls and is going
// the wrong way about it. RFC #1560 specifies the following:
Expand All @@ -1023,18 +1016,20 @@ ResolveItem::visit (AST::UseDeclaration &use_item)
// Which is the opposite of what we're doing if I understand correctly?

NodeId current_module = resolver->peek_current_module_scope ();
for (auto &path : to_resolve)
for (auto &import : to_resolve)
{
auto &path = import.get_path ();

rust_debug ("resolving use-decl path: [%s]", path.as_string ().c_str ());
NodeId resolved_node_id = ResolvePath::go (&path);
bool ok = resolved_node_id != UNKNOWN_NODEID;
if (!ok)
continue;

const AST::SimplePathSegment &final_seg = path.get_segments ().back ();
if (import.is_glob ())
continue;

auto decl
= CanonicalPath::new_seg (resolved_node_id, final_seg.as_string ());
auto decl = CanonicalPath::new_seg (resolved_node_id, import.get_name ());
mappings->insert_module_child_item (current_module, decl);

resolver->get_type_scope ().insert (decl, resolved_node_id,
Expand Down Expand Up @@ -1146,13 +1141,13 @@ rust_flatten_nested_glob (void)
= Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
foobar, UNDEF_LOCATION);

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_glob (glob, paths);
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_glob (glob, imports);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 1);
ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 1);
ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
}

static void
Expand All @@ -1164,12 +1159,12 @@ rust_flatten_glob (void)
= Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
frob, UNDEF_LOCATION);

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_glob (glob, paths);
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_glob (glob, imports);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 1);
ASSERT_EQ (paths[0], "frobulator");
ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 1);
ASSERT_EQ (imports[0].get_path (), "frobulator");
}

static void
Expand All @@ -1182,13 +1177,13 @@ rust_flatten_rebind_none (void)
auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE,
foobar, UNDEF_LOCATION);

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_rebind (rebind, paths);
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_rebind (rebind, imports);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 1);
ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 1);
ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
}

static void
Expand All @@ -1199,13 +1194,13 @@ rust_flatten_rebind (void)
auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
frob, UNDEF_LOCATION, {"saindoux"});

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_rebind (rebind, paths);
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_rebind (rebind, imports);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 2);
ASSERT_EQ (paths[0], "frobulator");
ASSERT_EQ (paths[1], "saindoux");
ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 1);
ASSERT_EQ (imports[0].get_path (), "frobulator");
ASSERT_EQ (imports[0].get_name (), "saindoux");
}

static void
Expand All @@ -1221,17 +1216,15 @@ rust_flatten_rebind_nested (void)
= Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
foo_bar_baz, UNDEF_LOCATION, {"saindoux"});

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_rebind (rebind, paths);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 2);
ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux");
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_rebind (rebind, imports);

ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 1);
ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
ASSERT_EQ (imports[0].get_path ().get_segments ()[2].as_string (), "baz");
ASSERT_EQ (imports[0].get_name (), "saindoux");
}

static void
Expand Down Expand Up @@ -1261,17 +1254,17 @@ rust_flatten_list (void)
= Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED, foo_bar,
std::move (uses), UNDEF_LOCATION);

auto paths = std::vector<Rust::AST::SimplePath> ();
Rust::Resolver::flatten_list (list, paths);

ASSERT_TRUE (!paths.empty ());
ASSERT_EQ (paths.size (), 2);
ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul");
auto imports = std::vector<Rust::Resolver::Import> ();
Rust::Resolver::flatten_list (list, imports);

ASSERT_TRUE (!imports.empty ());
ASSERT_EQ (imports.size (), 2);
ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
ASSERT_EQ (imports[0].get_path ().get_segments ()[2].as_string (), "baz");
ASSERT_EQ (imports[1].get_path ().get_segments ()[0].as_string (), "foo");
ASSERT_EQ (imports[1].get_path ().get_segments ()[1].as_string (), "bar");
ASSERT_EQ (imports[1].get_path ().get_segments ()[2].as_string (), "bul");
}

static void
Expand Down
23 changes: 23 additions & 0 deletions gcc/rust/resolve/rust-ast-resolve-item.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,29 @@ class ResolveExternItem : public ResolverBase
const CanonicalPath &canonical_prefix;
};

class Import
{
public:
Import (AST::SimplePath path, bool is_glob, std::string name)
: path (path), is_glob_f (is_glob), name (name)
{}

AST::SimplePath &get_path () { return path; }

const AST::SimplePath &get_path () const { return path; }

bool is_glob () const { return is_glob_f; }

const std::string &get_name () const { return name; }

void add_prefix (AST::SimplePath prefix);

private:
AST::SimplePath path;
bool is_glob_f;
std::string name;
};

} // namespace Resolver
} // namespace Rust

Expand Down
7 changes: 7 additions & 0 deletions gcc/testsuite/rust/compile/use_2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod foo {
pub struct S;
}

use foo::S as T;

const V: T = T; // { dg-warning "unused name" }
Loading