Skip to content

Commit

Permalink
Fix rebinding imports
Browse files Browse the repository at this point in the history
gcc/rust/ChangeLog:

	* resolve/rust-ast-resolve-item.cc
	(flatten_glob): Use Import class.
	(flatten_rebind): Likewise.
	(flatten_list): Likewise.
	(flatten): Likewise.
	(flatten_use_dec_to_paths): Likewise.
	(flatten_use_dec_to_imports): Likewise.
	(ResolveItem::visit): Likewise.
	(Import::add_prefix): New.
	(rust_flatten_nested_glob): Adjust test.
	(rust_flatten_glob): Likewise.
	(rust_flatten_rebind_none): Likewise.
	(rust_flatten_rebind): Likewise.
	(rust_flatten_rebind_nested): Likewise.
	(rust_flatten_list): Likewise.
	* resolve/rust-ast-resolve-item.h
	(class Import): New.

gcc/testsuite/ChangeLog:

	* rust/compile/use_2.rs: New test.

Signed-off-by: Owen Avery <[email protected]>
  • Loading branch information
powerboat9 authored and CohenArthur committed Feb 13, 2024
1 parent 1d8f5d5 commit 239247a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 93 deletions.
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 @@ -824,92 +824,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 @@ -930,21 +923,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 @@ -956,18 +949,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 @@ -1079,13 +1074,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 @@ -1097,12 +1092,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 @@ -1115,13 +1110,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 @@ -1132,13 +1127,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 @@ -1154,17 +1149,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 @@ -1194,17 +1187,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 @@ -124,6 +124,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" }

0 comments on commit 239247a

Please sign in to comment.