Skip to content

nr2.0: Improve visibility path handling #3785

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
12 changes: 11 additions & 1 deletion gcc/rust/resolve/rust-forever-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,13 @@ class ForeverStackStore
Node root;
};

enum class ResolutionMode
{
Normal,
FromRoot,
FromExtern, // extern prelude
};

template <Namespace N> class ForeverStack
{
public:
Expand Down Expand Up @@ -672,7 +679,7 @@ template <Namespace N> class ForeverStack
*/
template <typename S>
tl::optional<Rib::Definition> resolve_path (
const std::vector<S> &segments, bool has_opening_scope_resolution,
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors);

Expand Down Expand Up @@ -739,6 +746,9 @@ 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
tl::optional<Rib::Definition> get (Node &start, const Identifier &name);

/* Should we keep going upon seeing a Rib? */
enum class KeepGoing
{
Expand Down
103 changes: 53 additions & 50 deletions gcc/rust/resolve/rust-forever-stack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,12 @@ ForeverStack<N>::update_cursor (Node &new_cursor)

template <Namespace N>
tl::optional<Rib::Definition>
ForeverStack<N>::get (const Identifier &name)
ForeverStack<N>::get (Node &start, const Identifier &name)
{
tl::optional<Rib::Definition> resolved_definition = tl::nullopt;

// TODO: Can we improve the API? have `reverse_iter` return an optional?
reverse_iter ([&resolved_definition, &name] (Node &current) {
reverse_iter (start, [&resolved_definition, &name] (Node &current) {
auto candidate = current.rib.get (name.as_string ());

return candidate.map_or (
Expand All @@ -318,6 +318,13 @@ ForeverStack<N>::get (const Identifier &name)
return resolved_definition;
}

template <Namespace N>
tl::optional<Rib::Definition>
ForeverStack<N>::get (const Identifier &name)
{
return get (cursor (), name);
}

template <Namespace N>
tl::optional<Rib::Definition>
ForeverStack<N>::get_lang_prelude (const Identifier &name)
Expand Down Expand Up @@ -625,23 +632,25 @@ template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
ForeverStack<N>::resolve_path (
const std::vector<S> &segments, bool has_opening_scope_resolution,
const std::vector<S> &segments, ResolutionMode mode,
std::function<void (const S &, NodeId)> insert_segment_resolution,
std::vector<Error> &collect_errors)
{
rust_assert (!segments.empty ());

// handle paths with opening scopes
std::function<void (void)> cleanup_current = [] () {};
if (has_opening_scope_resolution)
std::reference_wrapper<Node> starting_point = cursor ();
switch (mode)
{
Node *last_current = &cursor_reference.get ();
if (get_rust_edition () == Edition::E2015)
cursor_reference = root;
else
cursor_reference = extern_prelude;
cleanup_current
= [this, last_current] () { cursor_reference = *last_current; };
case ResolutionMode::Normal:
break; // default
case ResolutionMode::FromRoot:
starting_point = root;
break;
case ResolutionMode::FromExtern:
starting_point = extern_prelude;
break;
default:
rust_unreachable ();
}

// if there's only one segment, we just use `get`
Expand All @@ -654,59 +663,53 @@ ForeverStack<N>::resolve_path (
lang_item.value ());

insert_segment_resolution (seg, seg_id);
cleanup_current ();
// TODO: does NonShadowable matter?
return Rib::Definition::NonShadowable (seg_id);
}

tl::optional<Rib::Definition> res
= get (unwrap_type_segment (segments.back ()).as_string ());
= get (starting_point.get (),
unwrap_type_segment (segments.back ()).as_string ());

if (!res)
res = get_lang_prelude (
unwrap_type_segment (segments.back ()).as_string ());

if (res && !res->is_ambiguous ())
insert_segment_resolution (segments.back (), res->get_node_id ());
cleanup_current ();
return res;
}

std::reference_wrapper<Node> starting_point = cursor ();
return find_starting_point (segments, starting_point,
insert_segment_resolution, collect_errors)
.and_then (
[this, &segments, &starting_point, &insert_segment_resolution,
&collect_errors] (typename std::vector<S>::const_iterator iterator) {
return resolve_segments (starting_point.get (), segments, iterator,
insert_segment_resolution, collect_errors);
})
.and_then ([this, &segments, &insert_segment_resolution] (
Node &final_node) -> tl::optional<Rib::Definition> {
// leave resolution within impl blocks to type checker
if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
return tl::nullopt;

auto &seg = unwrap_type_segment (segments.back ());
std::string seg_name = seg.as_string ();

// assuming this can't be a lang item segment
tl::optional<Rib::Definition> res
= resolve_final_segment (final_node, seg_name,
seg.is_lower_self_seg ());
// Ok we didn't find it in the rib, Lets try the prelude...
if (!res)
res = get_lang_prelude (seg_name);

auto res
= find_starting_point (segments, starting_point, insert_segment_resolution,
collect_errors)
.and_then (
[this, &segments, &starting_point, &insert_segment_resolution,
&collect_errors] (typename std::vector<S>::const_iterator iterator) {
return resolve_segments (starting_point.get (), segments, iterator,
insert_segment_resolution, collect_errors);
})
.and_then ([this, &segments, &insert_segment_resolution] (
Node &final_node) -> tl::optional<Rib::Definition> {
// leave resolution within impl blocks to type checker
if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
return tl::nullopt;

auto &seg = unwrap_type_segment (segments.back ());
std::string seg_name = seg.as_string ();

// assuming this can't be a lang item segment
tl::optional<Rib::Definition> res
= resolve_final_segment (final_node, seg_name,
seg.is_lower_self_seg ());
// Ok we didn't find it in the rib, Lets try the prelude...
if (!res)
res = get_lang_prelude (seg_name);

if (res && !res->is_ambiguous ())
insert_segment_resolution (segments.back (), res->get_node_id ());

return res;
});
cleanup_current ();
return res;
if (res && !res->is_ambiguous ())
insert_segment_resolution (segments.back (), res->get_node_id ());

return res;
});
}

template <Namespace N>
Expand Down
56 changes: 56 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 @@ -520,6 +520,62 @@ Late::visit (AST::TypePath &type)
Definition (resolved->get_node_id ()));
}

void
Late::visit (AST::Visibility &vis)
{
if (!vis.has_path ())
return;

AST::SimplePath &path = vis.get_path ();

rust_assert (path.get_segments ().size ());
auto &first_seg = path.get_segments ()[0];

auto mode = ResolutionMode::Normal;

if (path.has_opening_scope_resolution ())
{
if (get_rust_edition () == Edition::E2015)
mode = ResolutionMode::FromRoot;
else
mode = ResolutionMode::FromExtern;
}
else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg ()
&& !first_seg.is_lower_self_seg ())
{
if (get_rust_edition () == Edition::E2015)
{
mode = ResolutionMode::FromRoot;
}
else
{
rust_error_at (path.get_locus (),
"relative paths are not supported in visibilities in "
"2018 edition or later");
return;
}
}

auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types);

if (!res.has_value ())
{
rust_error_at (path.get_locus (), ErrorCode::E0433,
"could not resolve path %qs", path.as_string ().c_str ());
return;
}

// TODO: is this possible?
if (res->is_ambiguous ())
{
rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
path.as_string ().c_str ());
return;
}

ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ()));
}

void
Late::visit (AST::Trait &trait)
{
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/resolve/rust-late-name-resolver-2.0.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Late : public DefaultResolver
void visit (AST::LoopLabel &) override;
void visit (AST::PathInExpression &) override;
void visit (AST::TypePath &) override;
void visit (AST::Visibility &) override;
void visit (AST::Trait &) override;
void visit (AST::StructExprStruct &) override;
void visit (AST::StructExprStructBase &) override;
Expand Down
Loading