Skip to content
Draft
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/resolve/rust-default-resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "rust-ast-visitor.h"
#include "rust-ast.h"
#include "rust-attribute-values.h"
#include "rust-diagnostics.h"
#include "rust-item.h"
#include "rust-path.h"

Expand Down
130 changes: 121 additions & 9 deletions gcc/rust/resolve/rust-early-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,95 @@ bool
Early::resolve_rebind_import (NodeId use_dec_id,
TopLevel::ImportKind &&rebind_import)
{
rust_debug_loc (rebind_import.to_resolve.get_locus (),
"resolve_rebind_import called '%s'",
rebind_import.to_resolve.as_string ().c_str ());

NodeId import_id = UNKNOWN_NODEID;
auto &path = rebind_import.to_resolve;
auto &rebind = rebind_import.rebind.value ();

// rust_debug ("ARTHUR 1: %s", ctx.types.as_debug_string ().c_str ());

switch (rebind.get_new_bind_type ())
{
case AST::UseTreeRebind::NewBindType::IDENTIFIER:
// declared_name = rebind.get_identifier ().as_string ();
// locus = rebind.get_identifier ().get_locus ();
import_id = rebind.get_node_id ();
break;
case AST::UseTreeRebind::NewBindType::NONE:
{
const auto &segments = path.get_segments ();
// We don't want to insert `self` with `use module::self`
if (path.get_final_segment ().is_lower_self_seg ())
{
// Erroneous `self` or `{self}` use declaration
if (segments.size () == 1)
break;
import_id = segments[segments.size () - 2].get_node_id ();
}
else
{
import_id = path.get_final_segment ().get_node_id ();
}
break;
}
case AST::UseTreeRebind::NewBindType::WILDCARD:
// nothing
break;
}

if (ctx.lookup (import_id))
return true;

auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve);

// if we've found at least one definition, then we're good
if (definitions.empty ())
return false;

// if the last segment is `self`, then we need to insert the segment before
// that one as the definition
// if (rebind_import.to_resolve.get_final_segment ().is_lower_self_seg ())
// {
// auto second_to_last
// = rebind_import.to_resolve.get_segments ().size () - 2;

// rust_assert (second_to_last >= 0);

// auto mod_segment
// = rebind_import.to_resolve.get_segments ().at (second_to_last);
// auto resolved = ctx.lookup (mod_segment.get_node_id ());

// rust_assert (resolved);

// auto def = std::make_pair (Rib::Definition::Shadowable (*resolved),
// Namespace::Types);

// auto &imports = import_mappings.new_or_access (use_dec_id);

// imports.emplace_back (
// ImportPair (std::move (rebind_import), ImportData::Rebind ({def})));

// return true;
// }

auto &imports = import_mappings.new_or_access (use_dec_id);

rust_debug ("ARTHUR NS ns: %s",
definitions.front ().second == Namespace::Types ? "Types"
: "other :(");

imports.emplace_back (
ImportPair (std::move (rebind_import),
ImportData::Rebind (std::move (definitions))));

rust_debug_loc (rebind_import.to_resolve.get_locus (),
"finished resolve_rebind_import successfully");

// rust_debug ("ARTHUR 2: %s", ctx.types.as_debug_string ().c_str ());

return true;
}

Expand Down Expand Up @@ -392,15 +469,26 @@ Early::finalize_simple_import (const Early::ImportPair &mapping)
{
// FIXME: We probably need to store namespace information

auto locus = mapping.import_kind.to_resolve.get_locus ();
auto import = mapping.import_kind.to_resolve;
// auto import_id = Analysis::Mappings::get ().get_next_node_id ();
auto import_id = import.get_final_segment ().get_node_id ();
auto data = mapping.data;
auto identifier
= mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
auto identifier = import.get_final_segment ().get_segment_name ();

rust_debug ("[ARTHUR] RESOLVING IMPORT ``%s```",
mapping.import_kind.to_resolve.as_string ().c_str ());

for (auto &&definition : data.definitions ())
toplevel
.insert_or_error_out (
identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
{
dirty = true;

ctx.map_usage (Usage (import_id),
Definition (definition.first.get_node_id ()));

toplevel
.insert_or_error_out (identifier,
import.get_locus (), import_id, definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
}
}

void
Expand Down Expand Up @@ -428,11 +516,14 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping)
{
// We can fetch the value here as `resolve_rebind` will only be called on
// imports of the right kind
// auto import_id = Analysis::Mappings::get ().get_next_node_id ();
auto &path = mapping.import_kind.to_resolve;
auto &rebind = mapping.import_kind.rebind.value ();
auto data = mapping.data;

location_t locus = UNKNOWN_LOCATION;
NodeId import_id = UNKNOWN_NODEID;

std::string declared_name;

// FIXME: This needs to be done in `FinalizeImports`
Expand All @@ -441,6 +532,7 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping)
case AST::UseTreeRebind::NewBindType::IDENTIFIER:
declared_name = rebind.get_identifier ().as_string ();
locus = rebind.get_identifier ().get_locus ();
import_id = rebind.get_node_id ();
break;
case AST::UseTreeRebind::NewBindType::NONE:
{
Expand All @@ -452,9 +544,13 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping)
if (segments.size () == 1)
break;
declared_name = segments[segments.size () - 2].as_string ();
import_id = segments[segments.size () - 2].get_node_id ();
}
else
declared_name = path.get_final_segment ().as_string ();
{
declared_name = path.get_final_segment ().as_string ();
import_id = path.get_final_segment ().get_node_id ();
}
locus = path.get_final_segment ().get_locus ();
break;
}
Expand All @@ -463,9 +559,25 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping)
return;
}

// FIXME: This is a problem. We insert a definition as if it was the original
// definition, which means certain things that should error do not
//
// For example, the following is currently accepted by the compiler.
//
// mod foo { ... }
// use foo;

for (auto &&definition : data.definitions ())
toplevel.insert_or_error_out (
declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
{
dirty = true;

ctx.map_usage (Usage (import_id),
Definition (definition.first.get_node_id ()));

toplevel
.insert_or_error_out (declared_name,
path.get_locus (), import_id, definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
}
}

void
Expand Down
2 changes: 2 additions & 0 deletions gcc/rust/resolve/rust-late-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
#include "rust-ast-full.h"
#include "rust-diagnostics.h"
#include "rust-expr.h"
#include "rust-forever-stack.h"
#include "rust-hir-map.h"
#include "rust-late-name-resolver-2.0.h"
#include "rust-default-resolver.h"
#include "rust-name-resolution-context.h"
#include "rust-resolve-builtins.h"
#include "rust-path.h"
#include "rust-rib.h"
#include "rust-system.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
Expand Down
71 changes: 71 additions & 0 deletions gcc/rust/resolve/rust-name-resolution-context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
// <http://www.gnu.org/licenses/>.

#include "rust-name-resolution-context.h"
#include "expected.h"
#include "optional.h"
#include "rust-location.h"
#include "rust-mapping-common.h"

namespace Rust {
Expand Down Expand Up @@ -326,5 +328,74 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
}
}

enum class LookupFinalizeError
{
// Impossible - we did not find any definition corresponding to a Usage. This
// is an internal compiler error
NoDefinition,
// There was a loop in the map, such as an import resolving to another import
// which eventually resolved to the original import.
// Report the error and stop the pipeline
Loop,
};

static tl::expected<Definition, LookupFinalizeError>
find_leaf_definition (const Usage &key,
std::map<Usage, Definition> &resolved_nodes,
std::set<Usage> &keys_seen)
{
auto original_definition = resolved_nodes.find (key);
auto possible_import = Usage (original_definition->second.id);

if (original_definition == resolved_nodes.end ())
return tl::make_unexpected (LookupFinalizeError::NoDefinition);

if (!keys_seen.insert (key).second)
return tl::make_unexpected (LookupFinalizeError::Loop);

if (resolved_nodes.find (possible_import) == resolved_nodes.end ())
return original_definition->second;

// We're dealing with an import - a reference to another
// definition. Go through the chain and update the original key's
// corresponding definition.
return find_leaf_definition (possible_import, resolved_nodes, keys_seen);
}

void
NameResolutionContext::flatten ()
{
rust_debug ("[ARTHUR] FINALIZING EARLY NR!!!!");

for (auto &kv : resolved_nodes)
rust_debug ("[ARTHUR] [resolved_nodes]: %d -> %d", kv.first.id,
kv.second.id);

for (auto &k_v : resolved_nodes)
{
// Loop detection
auto keys_seen = std::set<Usage> ();

auto result = find_leaf_definition (k_v.first, resolved_nodes, keys_seen);

if (!result)
{
// Trigger an ICE if we haven't found a definition because that's
// really weird
rust_assert (result.error () != LookupFinalizeError::NoDefinition);

rust_error_at (UNDEF_LOCATION, "import loop");
continue;
}

// Replace the Definition for this Usage in the map. This may be a no-op.
k_v.second = result.value ();
}

for (auto &kv : resolved_nodes)
rust_debug ("[ARTHUR] [resolved_nodes]: %d -> %d", kv.first.id,
kv.second.id);
}

} // namespace Resolver2_0
} // namespace Rust
19 changes: 19 additions & 0 deletions gcc/rust/resolve/rust-name-resolution-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,25 @@ class NameResolutionContext
/* If declared with #[prelude_import], the current standard library module */
tl::optional<NodeId> prelude;

/**
* We've now collected every definition and import, and errored out when
* necessary if multiple definitions are colliding. Do a final flattening of
* the name resolution context to make it easier to digest for the late name
* resolution and type-checker. This basically turns the `resolved_nodes` map
* from a linked-list-like map to a regular, flat hashmap.
*
* FIXME: The documentation is wrong, this needs to also run after all usages
* have been *resolved* so after Late as well!!!
*
* TODO: Should this return something like the ImmutableNameResolutionCtx? Or
* set it up at least? And instead of mutating the `resolved_nodes` map,
* create a new one for the ImmutableNameResolutionCtx?
* Actually, since Late uses the NRCtx directly we should mutate this. Most
* later passes don't look at this map. So let's go for side-effects in a void
* function, yipee.
*/
void flatten ();

private:
/* Map of "usage" nodes which have been resolved to a "definition" node */
std::map<Usage, Definition> resolved_nodes;
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/resolve/rust-resolve-builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.

#include "rust-resolve-builtins.h"
#include "optional.h"
#include "rust-name-resolution-context.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
Expand Down
2 changes: 2 additions & 0 deletions gcc/rust/resolve/rust-resolve-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#ifndef RUST_RESOLVE_BUILTINS_H
#define RUST_RESOLVE_BUILTINS_H

#include "rust-hir-map.h"

namespace Rust {
namespace Resolver2_0 {

Expand Down
Loading
Loading