Skip to content
Open
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
8 changes: 8 additions & 0 deletions gcc/rust/resolve/rust-early-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ Early::finalize_glob_import (NameResolutionContext &ctx,

rust_assert (container);

if (mapping.import_kind.is_prelude)
{
rust_assert (container.value ()->get_item_kind ()
== AST::Item::Kind::Module);

ctx.prelude = container.value ()->get_node_id ();
}

GlobbingVisitor (ctx).go (container.value ());
}

Expand Down
20 changes: 19 additions & 1 deletion gcc/rust/resolve/rust-forever-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,8 @@ template <Namespace N> class ForeverStack
tl::optional<Rib::Definition> get (const Identifier &name);
tl::optional<Rib::Definition> get_lang_prelude (const Identifier &name);
tl::optional<Rib::Definition> get_lang_prelude (const std::string &name);
tl::optional<Rib::Definition> get_from_prelude (NodeId prelude,
const Identifier &name);

/**
* Resolve a path to its definition in the current `ForeverStack`
Expand All @@ -682,6 +684,11 @@ template <Namespace N> class ForeverStack
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors);
template <typename S>
tl::optional<Rib::Definition> resolve_path (
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors, NodeId starting_point_id);

// FIXME: Documentation
tl::optional<Rib &> to_rib (NodeId rib_id);
Expand Down Expand Up @@ -743,9 +750,19 @@ template <Namespace N> class ForeverStack
tl::optional<Node &> parent; // `None` only if the node is a root
};

// private overload which allows specifying a starting point
/**
* Private overloads which allow specifying a starting point
*/

tl::optional<Rib::Definition> get (Node &start, const Identifier &name);

template <typename S>
tl::optional<Rib::Definition> resolve_path (
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors,
std::reference_wrapper<Node> starting_point);

/* Should we keep going upon seeing a Rib? */
enum class KeepGoing
{
Expand Down Expand Up @@ -777,6 +794,7 @@ template <Namespace N> class ForeverStack
* resolution
*/
Node lang_prelude;

/*
* The extern prelude, used for resolving external crates
*/
Expand Down
46 changes: 45 additions & 1 deletion gcc/rust/resolve/rust-forever-stack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,17 @@ ForeverStack<N>::get_lang_prelude (const std::string &name)
return lang_prelude.rib.get (name);
}

template <Namespace N>
tl::optional<Rib::Definition>
ForeverStack<N>::get_from_prelude (NodeId prelude, const Identifier &name)
{
auto starting_point = dfs_node (root, prelude);
if (!starting_point)
return tl::nullopt;

return get (*starting_point, name);
}

template <>
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
const Identifier &name)
Expand Down Expand Up @@ -647,17 +658,50 @@ ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
return final_node.rib.get (seg_name);
}

template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
ForeverStack<N>::resolve_path (
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors, NodeId starting_point_id)
{
auto starting_point = dfs_node (root, starting_point_id);

// We may have a prelude, but haven't visited it yet and thus it's not in our
// nodes
if (!starting_point)
return tl::nullopt;

return resolve_path (segments, mode, insert_segment_resolution,
collect_errors, *starting_point);
}

template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
ForeverStack<N>::resolve_path (
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors)
{
std::reference_wrapper<Node> starting_point = cursor ();

return resolve_path (segments, mode, insert_segment_resolution,
collect_errors, starting_point);
}

template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
ForeverStack<N>::resolve_path (
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors,
std::reference_wrapper<Node> starting_point)
{
rust_assert (!segments.empty ());

std::reference_wrapper<Node> starting_point = cursor ();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably just add a new variant to ResolutionMode, instead of adding a user-provided starting_point in addition to mode

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ForeverStack could probably fetch the node id associated with the language prelude from NameResolutionContext -- might be kind of tricky to get that working, though. You could also just have each ForeverStack keep a std::reference_wrapper to the currently set prelude Node.

switch (mode)
{
case ResolutionMode::Normal:
Expand Down
12 changes: 11 additions & 1 deletion gcc/rust/resolve/rust-late-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,17 @@ Late::visit (AST::IdentifierExpr &expr)
{
resolved = type;
}
else
else if (!resolved && ctx.prelude)
{
resolved
= ctx.values.get_from_prelude (*ctx.prelude, expr.get_ident ());

if (!resolved)
resolved
= ctx.types.get_from_prelude (*ctx.prelude, expr.get_ident ());
}

if (!resolved)
{
rust_error_at (expr.get_locus (), ErrorCode::E0425,
"cannot find value %qs in this scope",
Expand Down
59 changes: 51 additions & 8 deletions gcc/rust/resolve/rust-name-resolution-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,23 +560,63 @@ class NameResolutionContext
if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
map_usage (Usage (seg_id), Definition (id));
};

tl::optional<Rib::Definition> resolved = tl::nullopt;

switch (ns)
{
case Namespace::Values:
return values.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
resolved
= values.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
break;
case Namespace::Types:
return types.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
resolved
= types.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
break;
case Namespace::Macros:
return macros.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
resolved
= macros.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
break;
case Namespace::Labels:
return labels.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
resolved
= labels.resolve_path (segments, mode, insert_segment_resolution,
collect_errors);
break;
default:
rust_unreachable ();
}

// If it fails, switch to std prelude resolution if it exists
if (prelude && !resolved)
{
// TODO: Factor this with the above
switch (ns)
{
case Namespace::Values:
return values.resolve_path (segments, mode,
insert_segment_resolution,
collect_errors, *prelude);
case Namespace::Types:
return types.resolve_path (segments, mode,
insert_segment_resolution,
collect_errors, *prelude);
case Namespace::Macros:
return macros.resolve_path (segments, mode,
insert_segment_resolution,
collect_errors, *prelude);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably use a temporary vector instead of collect_errors for the prelude resolution -- if prelude resolution does emit errors and fail, only the errors produced during the normal resolution attempt should be collected.

case Namespace::Labels:
return labels.resolve_path (segments, mode,
insert_segment_resolution,
collect_errors, *prelude);
default:
rust_unreachable ();
}
}

return resolved;
}

template <typename S, typename... Args>
Expand Down Expand Up @@ -676,6 +716,9 @@ class NameResolutionContext
std::forward<Args> (args)...);
}

/* If declared with #[prelude_import], the current standard library module */
tl::optional<NodeId> prelude;

private:
/* Map of "usage" nodes which have been resolved to a "definition" node */
std::map<Usage, Definition> resolved_nodes;
Expand Down
13 changes: 12 additions & 1 deletion gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,16 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths,
paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ()));
}

static bool
has_prelude_import (const std::vector<AST::Attribute> &attributes)
{
for (const auto &attr : attributes)
if (attr.get_path ().as_string () == "prelude_import")
return true;

return false;
}

void
TopLevel::visit (AST::UseDeclaration &use)
{
Expand Down Expand Up @@ -523,7 +533,8 @@ TopLevel::visit (AST::UseDeclaration &use)

for (auto &&glob : glob_path)
imports.emplace_back (
ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib));
ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib,
has_prelude_import (use.get_outer_attrs ())));

for (auto &&rebind : rebind_path)
imports.emplace_back (
Expand Down
18 changes: 12 additions & 6 deletions gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ class TopLevel : public DefaultResolver
} kind;

static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib,
Rib &types_rib, Rib &macros_rib)
Rib &types_rib, Rib &macros_rib, bool is_prelude)
{
return ImportKind (Kind::Glob, std::move (to_resolve), values_rib,
types_rib, macros_rib);
types_rib, macros_rib, is_prelude);
}

static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib,
Expand All @@ -84,8 +84,10 @@ class TopLevel : public DefaultResolver
AST::UseTreeRebind &&rebind, Rib &values_rib,
Rib &types_rib, Rib &macros_rib)
{
return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib,
types_rib, macros_rib, std::move (rebind));
return ImportKind (
Kind::Rebind, std::move (to_resolve), values_rib, types_rib, macros_rib,
false /* is_prelude: rebind imports can never be preludes */,
std::move (rebind));
}

// The path for `Early` to resolve.
Expand All @@ -98,13 +100,17 @@ class TopLevel : public DefaultResolver
Rib &types_rib;
Rib &macros_rib;

// Can only be true if we are dealing with a glob import with the
// #[prelude_import] attribute
bool is_prelude = false;

private:
ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib,
Rib &types_rib, Rib &macros_rib,
Rib &types_rib, Rib &macros_rib, bool is_prelude = false,
tl::optional<AST::UseTreeRebind> &&rebind = tl::nullopt)
: kind (kind), to_resolve (std::move (to_resolve)),
rebind (std::move (rebind)), values_rib (values_rib),
types_rib (types_rib), macros_rib (macros_rib)
types_rib (types_rib), macros_rib (macros_rib), is_prelude (is_prelude)
{}
};

Expand Down
Loading