diff options
-rw-r--r-- | gcc/rust/resolve/rust-forever-stack.h | 12 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-forever-stack.hxx | 82 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 33 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-name-resolution-context.cc | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-rib.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/issue-3315-1.rs | 8 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/issue-3315-2.rs | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/nr2/exclude | 1 |
8 files changed, 127 insertions, 25 deletions
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 22efc97..2a4c734 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -548,6 +548,7 @@ template <Namespace N> class ForeverStack public: ForeverStack () : root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)), + prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)), cursor_reference (root) { rust_assert (root.is_root ()); @@ -657,6 +658,8 @@ public: * the current map, an empty one otherwise. */ tl::optional<Rib::Definition> get (const Identifier &name); + tl::optional<Rib::Definition> get_prelude (const Identifier &name); + tl::optional<Rib::Definition> get_prelude (const std::string &name); /** * Resolve a path to its definition in the current `ForeverStack` @@ -721,6 +724,7 @@ private: {} bool is_root () const; + bool is_prelude () const; bool is_leaf () const; void insert_child (Link link, Node child); @@ -756,7 +760,15 @@ private: const Node &cursor () const; void update_cursor (Node &new_cursor); + /* The forever stack's actual nodes */ Node root; + /* + * A special prelude node used currently for resolving language builtins + * It has the root node as a parent, and acts as a "special case" for name + * resolution + */ + Node prelude; + std::reference_wrapper<Node> cursor_reference; void stream_rib (std::stringstream &stream, const Rib &rib, diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 90e0ceb..a6e0b30 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -36,6 +36,13 @@ ForeverStack<N>::Node::is_root () const template <Namespace N> bool +ForeverStack<N>::Node::is_prelude () const +{ + return rib.kind == Rib::Kind::Prelude; +} + +template <Namespace N> +bool ForeverStack<N>::Node::is_leaf () const { return children.empty (); @@ -63,6 +70,16 @@ template <Namespace N> void ForeverStack<N>::push_inner (Rib rib, Link link) { + if (rib.kind == Rib::Kind::Prelude) + { + // If you push_inner into the prelude from outside the root, you will pop + // back into the root, which could screw up a traversal. + rust_assert (&cursor_reference.get () == &root); + // Prelude doesn't have an access path + rust_assert (!link.path); + update_cursor (this->prelude); + return; + } // If the link does not exist, we create it and emplace a new `Node` with the // current node as its parent. `unordered_map::emplace` returns a pair with // the iterator and a boolean. If the value already exists, the iterator @@ -300,6 +317,20 @@ ForeverStack<N>::get (const Identifier &name) return resolved_definition; } +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_prelude (const Identifier &name) +{ + return prelude.rib.get (name.as_string ()); +} + +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_prelude (const std::string &name) +{ + return prelude.rib.get (name); +} + template <> tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get ( const Identifier &name) @@ -399,7 +430,7 @@ ForeverStack<N>::find_starting_point ( break; auto &seg = unwrap_type_segment (outer_seg); - auto is_self_or_crate + bool is_self_or_crate = seg.is_crate_path_seg () || seg.is_lower_self_seg (); // if we're after the first path segment and meet `self` or `crate`, it's @@ -457,7 +488,7 @@ ForeverStack<N>::resolve_segments ( typename std::vector<S>::const_iterator iterator, std::function<void (const S &, NodeId)> insert_segment_resolution) { - auto *current_node = &starting_point; + Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) { auto &outer_seg = *iterator; @@ -473,7 +504,7 @@ ForeverStack<N>::resolve_segments ( } auto &seg = unwrap_type_segment (outer_seg); - auto str = seg.as_string (); + std::string str = seg.as_string (); rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ()); // check that we don't encounter *any* leading keywords afterwards @@ -488,10 +519,20 @@ ForeverStack<N>::resolve_segments ( * On every iteration this loop either * * 1. terminates - * 2. decreases the depth of the node pointed to by current_node * - * This ensures termination + * 2. decreases the depth of the node pointed to by current_node until + * current_node reaches the root + * + * 3. If the root node is reached, and we were not able to resolve the + * segment, we search the prelude rib for the segment, by setting + * current_node to point to the prelude, and toggling the + * searched_prelude boolean to true. If current_node is the prelude + * rib, and searched_prelude is true, we will exit. + * + * This ensures termination. + * */ + bool searched_prelude = false; while (true) { // may set the value of child @@ -527,9 +568,16 @@ ForeverStack<N>::resolve_segments ( } } + if (current_node->is_root () && !searched_prelude) + { + searched_prelude = true; + current_node = &prelude; + continue; + } + if (!is_start (iterator, segments) || current_node->rib.kind == Rib::Kind::Module - || current_node->is_root ()) + || current_node->is_prelude ()) { return tl::nullopt; } @@ -569,7 +617,12 @@ ForeverStack<N>::resolve_path ( return Rib::Definition::NonShadowable (seg_id); } - auto res = get (unwrap_type_segment (segments.back ()).as_string ()); + tl::optional<Rib::Definition> res + = get (unwrap_type_segment (segments.back ()).as_string ()); + + if (!res) + res = get_prelude (unwrap_type_segment (segments.back ()).as_string ()); + if (res && !res->is_ambiguous ()) insert_segment_resolution (segments.back (), res->get_node_id ()); return res; @@ -584,16 +637,25 @@ ForeverStack<N>::resolve_path ( return resolve_segments (starting_point.get (), segments, iterator, insert_segment_resolution); }) - .and_then ([&segments, &insert_segment_resolution] ( + .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; + + std::string seg_name + = unwrap_type_segment (segments.back ()).as_string (); + // assuming this can't be a lang item segment - auto res = final_node.rib.get ( - unwrap_type_segment (segments.back ()).as_string ()); + tl::optional<Rib::Definition> res = final_node.rib.get (seg_name); + + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_prelude (seg_name); + if (res && !res->is_ambiguous ()) insert_segment_resolution (segments.back (), res->get_node_id ()); + return res; }); } diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 9cf2b1f..f4ad53a 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -91,16 +91,18 @@ Late::setup_builtin_types () // insert it in the type context... }; - for (const auto &builtin : builtins) - { - // we should be able to use `insert_at_root` or `insert` here, since we're - // at the root :) hopefully! - auto ok = ctx.types.insert (builtin.name, builtin.node_id); - rust_assert (ok); - - ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id); - ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type); - } + // There's a special Rib for putting prelude items, since prelude items need + // to satisfy certain special rules. + ctx.scoped (Rib::Kind::Prelude, 0, [this, &ty_ctx] (void) -> void { + for (const auto &builtin : builtins) + { + auto ok = ctx.types.insert (builtin.name, builtin.node_id); + rust_assert (ok); + + ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id); + ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type); + } + }); // ...here! auto *unit_type = TyTy::TupleType::get_unit_type (); @@ -213,7 +215,6 @@ Late::visit (AST::IdentifierExpr &expr) // TODO: same thing as visit(PathInExpression) here? tl::optional<Rib::Definition> resolved = tl::nullopt; - if (auto value = ctx.values.get (expr.get_ident ())) { resolved = value; @@ -231,10 +232,12 @@ Late::visit (AST::IdentifierExpr &expr) } else { - rust_error_at (expr.get_locus (), - "could not resolve identifier expression: %qs", - expr.get_ident ().as_string ().c_str ()); - return; + if (auto typ = ctx.types.get_prelude (expr.get_ident ())) + resolved = typ; + else + rust_error_at (expr.get_locus (), + "could not resolve identifier expression: %qs", + expr.get_ident ().as_string ().c_str ()); } ctx.map_usage (Usage (expr.get_node_id ()), diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 517a483..92c4863 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -113,6 +113,7 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id, std::function<void (void)> lambda, tl::optional<Identifier> path) { + // NOTE: You must be at the root node when pushing the prelude rib. values.push (rib_kind, id, path); types.push (rib_kind, id, path); macros.push (rib_kind, id, path); @@ -132,6 +133,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns, std::function<void (void)> lambda, tl::optional<Identifier> path) { + // This could work... I'm not sure why you would want to do this though. + rust_assert (rib_kind != Rib::Kind::Prelude); + switch (ns) { case Namespace::Values: diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index ccc4c27..c498328 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -183,6 +183,11 @@ public: ForwardTypeParamBan, /* Const generic, as in the following example: fn foo<T, const X: T>() {} */ ConstParamType, + /* Prelude rib, used for both the language prelude (i32,usize,etc) and the + * (future) {std,core}::prelude::* import. A regular rib with the + * restriction that you cannot `use` items from the Prelude + */ + Prelude, } kind; static std::string kind_to_string (Rib::Kind kind) diff --git a/gcc/testsuite/rust/compile/issue-3315-1.rs b/gcc/testsuite/rust/compile/issue-3315-1.rs new file mode 100644 index 0000000..07581da --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3315-1.rs @@ -0,0 +1,8 @@ +//You should be able to create a module of the same name as a builtin type + +mod i32 { +} + +fn main() -> isize { + 0 +} diff --git a/gcc/testsuite/rust/compile/issue-3315-2.rs b/gcc/testsuite/rust/compile/issue-3315-2.rs new file mode 100644 index 0000000..71abd6c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3315-2.rs @@ -0,0 +1,7 @@ +mod i32 { +} + +fn main() -> isize { + let i:i32 = 0 as i32; + i as isize +} diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index d36c24b..a4bac9a 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -13,6 +13,7 @@ issue-2330.rs issue-2812.rs issue-850.rs issue-855.rs +issue-3315-2.rs iterators1.rs lookup_err1.rs macros/mbe/macro43.rs |