// Copyright (C) 2020-2024 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #ifndef RUST_RIB_H #define RUST_RIB_H #include "rust-system.h" #include "rust-ast.h" #include "optional.h" #include "expected.h" namespace Rust { namespace Resolver2_0 { /** pub enum Namespace { /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s /// (and, by extension, crates). /// /// Note that the type namespace includes other items; this is not an /// exhaustive list. TypeNS, /// The value namespace includes `fn`s, `const`s, `static`s, and local variables (including function arguments). ValueNS, /// The macro namespace includes `macro_rules!` macros, declarative `macro`s, /// procedural macros, attribute macros, `derive` macros, and non-macro attributes /// like `#[inline]` and `#[rustfmt::skip]`. MacroNS, } */ // FIXME: There's no `labels` namespace, not sure if we need one or how to keep // one // FIXME: And where are things like loop labels kept? /** * All namespaces that Rust's name resolution needs to handle */ // TODO: Move to `rust-forever-stack.h`? enum class Namespace { Values, Types, Labels, Macros, // TODO: Which namespaces are we missing? }; /** * Error returned by `Rib::insert` when the key was already present in the Rib's * map. The class contains the previously-inserted NodeId as well as the name of * the node. */ struct DuplicateNameError { // TODO: We might need multiple kinds of errors later down the line DuplicateNameError (std::string name, NodeId existing); std::string name; NodeId existing; }; /** * A rib is a container of nodes, either declaration or usages, as well as the * identifier each node uses. They are used to delimit lexical scopes, and have * an impact on name resolution - they restrict certain name accesses and serve * as boundaries between scopes. * For example, if we are resolving the following *variable* use: * * ```rust * fn outer() { * let a = 15; // decl * fn inner() -> i32 { * a // use * } * } * ``` * * The `Function` rib we will have pushed will restrict the access to `outer`'s * `a` declaration: Variable uses cannot cross function boundaries. On the other * hand, if we were resolving a type usage, this would be perfectly allowed. */ class Rib { public: enum class Kind { Normal, Module, Function, ConstantItem, // -> this variant has a boolean TraitOrImpl, /* Any item other than a Module, Function, Constant, Trait or Impl block */ Item, Closure, MacroDefinition, /* Ban the use of forward-declared generic parameters in defaults */ ForwardTypeParamBan, /* Const generic, as in the following example: fn foo() {} */ ConstParamType, } kind; Rib (Kind kind); Rib (Kind kind, std::string identifier, NodeId id); Rib (Kind kind, std::unordered_map values); // TODO: What's the correctbehavior if the key already exists? What if a decl // and use are in the same rib? Is that possible? Okay based on RibKind? /** * Insert a new node in the rib * * @param name The name associated with the AST node * @param id Its NodeId * @param can_shadow If the newly inserted value can shadow an existing one * * @return `DuplicateNameError` if the node is already present in the rib. The * `DuplicateNameError` class contains the NodeId of the existing * node. Returns the new NodeId on success. */ tl::expected insert (std::string name, NodeId id, bool can_shadow = false); /** * Access an inserted NodeId. * * @return tl::nullopt if the key does not exist, the NodeId otherwise */ tl::optional get (const std::string &name); /* View all the values stored in the rib */ const std::unordered_map &get_values () const; private: std::unordered_map values; }; } // namespace Resolver2_0 } // namespace Rust #endif // !RUST_RIB_H