Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #ifndef RUST_RIB_H
20 : : #define RUST_RIB_H
21 : :
22 : : #include "rust-system.h"
23 : : #include "rust-ast.h"
24 : : #include "optional.h"
25 : : #include "expected.h"
26 : :
27 : : namespace Rust {
28 : : namespace Resolver2_0 {
29 : :
30 : : /**
31 : :
32 : : pub enum Namespace {
33 : : /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and
34 : : `mod`s
35 : : /// (and, by extension, crates).
36 : : ///
37 : : /// Note that the type namespace includes other items; this is not an
38 : : /// exhaustive list.
39 : : TypeNS,
40 : : /// The value namespace includes `fn`s, `const`s, `static`s, and local
41 : : variables (including function arguments). ValueNS,
42 : : /// The macro namespace includes `macro_rules!` macros, declarative `macro`s,
43 : : /// procedural macros, attribute macros, `derive` macros, and non-macro
44 : : attributes
45 : : /// like `#[inline]` and `#[rustfmt::skip]`.
46 : : MacroNS,
47 : : }
48 : :
49 : : */
50 : :
51 : : // FIXME: There's no `labels` namespace, not sure if we need one or how to keep
52 : : // one
53 : : // FIXME: And where are things like loop labels kept?
54 : :
55 : : /**
56 : : * All namespaces that Rust's name resolution needs to handle
57 : : */
58 : : // TODO: Move to `rust-forever-stack.h`?
59 : : enum class Namespace
60 : : {
61 : : Values,
62 : : Types,
63 : : Labels,
64 : : Macros,
65 : : // TODO: Which namespaces are we missing?
66 : : };
67 : :
68 : : /**
69 : : * Error returned by `Rib::insert` when the key was already present in the Rib's
70 : : * map. The class contains the previously-inserted NodeId as well as the name of
71 : : * the node.
72 : : */
73 : 0 : struct DuplicateNameError
74 : : {
75 : : // TODO: We might need multiple kinds of errors later down the line
76 : : DuplicateNameError (std::string name, NodeId existing);
77 : :
78 : : std::string name;
79 : : NodeId existing;
80 : : };
81 : :
82 : : /**
83 : : * A rib is a container of nodes, either declaration or usages, as well as the
84 : : * identifier each node uses. They are used to delimit lexical scopes, and have
85 : : * an impact on name resolution - they restrict certain name accesses and serve
86 : : * as boundaries between scopes.
87 : :
88 : : * For example, if we are resolving the following *variable* use:
89 : : *
90 : : * ```rust
91 : : * fn outer() {
92 : : * let a = 15; // decl
93 : : * fn inner() -> i32 {
94 : : * a // use
95 : : * }
96 : : * }
97 : : * ```
98 : : *
99 : : * The `Function` rib we will have pushed will restrict the access to `outer`'s
100 : : * `a` declaration: Variable uses cannot cross function boundaries. On the other
101 : : * hand, if we were resolving a type usage, this would be perfectly allowed.
102 : : */
103 : 45280 : class Rib
104 : : {
105 : : public:
106 : : enum class Kind
107 : : {
108 : : Normal,
109 : : Module,
110 : : Function,
111 : : ConstantItem, // -> this variant has a boolean
112 : : TraitOrImpl,
113 : : /* Any item other than a Module, Function, Constant, Trait or Impl block */
114 : : Item,
115 : : Closure,
116 : : MacroDefinition,
117 : : /* Ban the use of forward-declared generic parameters in defaults */
118 : : ForwardTypeParamBan,
119 : : /* Const generic, as in the following example: fn foo<T, const X: T>() {} */
120 : : ConstParamType,
121 : : } kind;
122 : :
123 : : Rib (Kind kind);
124 : : Rib (Kind kind, std::string identifier, NodeId id);
125 : : Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
126 : :
127 : : // TODO: What's the correctbehavior if the key already exists? What if a decl
128 : : // and use are in the same rib? Is that possible? Okay based on RibKind?
129 : :
130 : : /**
131 : : * Insert a new node in the rib
132 : : *
133 : : * @param name The name associated with the AST node
134 : : * @param id Its NodeId
135 : : * @param can_shadow If the newly inserted value can shadow an existing one
136 : : *
137 : : * @return `DuplicateNameError` if the node is already present in the rib. The
138 : : * `DuplicateNameError` class contains the NodeId of the existing
139 : : * node. Returns the new NodeId on success.
140 : : */
141 : : tl::expected<NodeId, DuplicateNameError> insert (std::string name, NodeId id,
142 : : bool can_shadow = false);
143 : :
144 : : /**
145 : : * Access an inserted NodeId.
146 : : *
147 : : * @return tl::nullopt if the key does not exist, the NodeId otherwise
148 : : */
149 : : tl::optional<NodeId> get (const std::string &name);
150 : :
151 : : /* View all the values stored in the rib */
152 : : const std::unordered_map<std::string, NodeId> &get_values () const;
153 : :
154 : : private:
155 : : std::unordered_map<std::string, NodeId> values;
156 : : };
157 : :
158 : : } // namespace Resolver2_0
159 : : } // namespace Rust
160 : :
161 : : #endif // !RUST_RIB_H
|