Line data Source code
1 : // Copyright (C) 2020-2026 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 322319 : 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 4570399 : class Rib
104 : {
105 : public:
106 : // TODO: Rename the class? to what? Binding? Declaration?
107 : // This is useful for items which are in namespaces where shadowing is not
108 : // allowed, but which are still shadowable! for example, when you do a glob
109 : // import, if a later import has the same name as an item imported in the glob
110 : // import, that glob imported item will need to get shadowed
111 : class Definition
112 : {
113 : public:
114 : static Definition NonShadowable (NodeId id, bool enum_variant = false);
115 : static Definition Shadowable (NodeId id);
116 : static Definition Globbed (NodeId id);
117 :
118 : // checked shadowable -> non_shadowable -> globbed
119 : // we have shadowable *and* globbed in order to control
120 : // resolution priority
121 : // we *could* use a single vector with 2 indices here
122 : // but it's probably not worth it for now
123 : std::vector<NodeId> ids_shadowable;
124 : std::vector<NodeId> ids_non_shadowable;
125 : std::vector<NodeId> ids_globbed;
126 :
127 : // Enum variant should be skipped when dealing with inner definition.
128 : // struct E2;
129 : //
130 : // enum MyEnum<T> /* <-- Should be kept */{
131 : // E2 /* <-- Should be skipped */ (E2);
132 : // }
133 : bool enum_variant;
134 :
135 162062 : Definition () = default;
136 :
137 159021 : Definition &operator= (const Definition &) = default;
138 773166 : Definition (Definition const &) = default;
139 :
140 : bool is_variant () const;
141 :
142 : bool is_ambiguous () const;
143 :
144 248935 : NodeId get_node_id () const
145 : {
146 248935 : if (!ids_shadowable.empty ())
147 26616 : return ids_shadowable.back ();
148 :
149 222319 : rust_assert (!is_ambiguous ());
150 :
151 222319 : if (!ids_non_shadowable.empty ())
152 222303 : return ids_non_shadowable.back ();
153 :
154 16 : rust_assert (!ids_globbed.empty ());
155 16 : return ids_globbed.back ();
156 : }
157 :
158 : std::string to_string () const;
159 :
160 : private:
161 : enum class Mode
162 : {
163 : SHADOWABLE,
164 : NON_SHADOWABLE,
165 : GLOBBED
166 : };
167 :
168 : Definition (NodeId id, Mode mode, bool enum_variant);
169 : };
170 :
171 : enum class Kind
172 : {
173 : Normal,
174 : Module,
175 : Function,
176 : ConstantItem, // -> this variant has a boolean
177 : TraitOrImpl,
178 : /* Any item other than a Module, Function, Constant, Trait or Impl block */
179 : Item,
180 : Closure,
181 : MacroDefinition,
182 : /* Ban the use of forward-declared generic parameters in defaults */
183 : ForwardTypeParamBan,
184 : /* Const generic, as in the following example: fn foo<T, const X: T>() {} */
185 : ConstParamType,
186 : /* Prelude rib, used for both the language prelude (i32,usize,etc) and the
187 : * (future) {std,core}::prelude::* import. A regular rib with the
188 : * restriction that you cannot `use` items from the Prelude
189 : */
190 : Prelude,
191 : /* Generic rib, used to store generics */
192 : Generics,
193 : } kind;
194 :
195 0 : static std::string kind_to_string (Rib::Kind kind)
196 : {
197 0 : switch (kind)
198 : {
199 0 : case Rib::Kind::Normal:
200 0 : return "Normal";
201 0 : case Rib::Kind::Module:
202 0 : return "Module";
203 0 : case Rib::Kind::Function:
204 0 : return "Function";
205 0 : case Rib::Kind::ConstantItem:
206 0 : return "ConstantItem";
207 0 : case Rib::Kind::TraitOrImpl:
208 0 : return "TraitOrImpl";
209 0 : case Rib::Kind::Item:
210 0 : return "Item";
211 0 : case Rib::Kind::Closure:
212 0 : return "Closure";
213 0 : case Rib::Kind::MacroDefinition:
214 0 : return "Macro definition";
215 0 : case Rib::Kind::ForwardTypeParamBan:
216 0 : return "Forward type param ban";
217 0 : case Rib::Kind::ConstParamType:
218 0 : return "Const Param Type";
219 0 : case Kind::Prelude:
220 0 : return "Prelude";
221 0 : case Kind::Generics:
222 0 : return "Generics";
223 : }
224 :
225 0 : rust_unreachable ();
226 : }
227 :
228 : Rib (Kind kind);
229 : Rib (Kind kind, std::string identifier, NodeId id);
230 : Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
231 :
232 : // TODO: What's the correctbehavior if the key already exists? What if a decl
233 : // and use are in the same rib? Is that possible? Okay based on RibKind?
234 :
235 : /**
236 : * Insert a new node in the rib
237 : *
238 : * @param name The name associated with the AST node
239 : * @param def The `Definition` to insert
240 : *
241 : * @return `DuplicateNameError` if the node is already present in the rib. The
242 : * `DuplicateNameError` class contains the NodeId of the existing
243 : * node. Returns the new NodeId on success.
244 : */
245 : tl::expected<NodeId, DuplicateNameError> insert (std::string name,
246 : Definition def);
247 :
248 : /**
249 : * Access an inserted NodeId.
250 : *
251 : * @return tl::nullopt if the key does not exist, the NodeId otherwise
252 : */
253 : tl::optional<Rib::Definition> get (const std::string &name);
254 :
255 : /* View all the values stored in the rib */
256 : const std::unordered_map<std::string, Definition> &get_values () const;
257 :
258 : private:
259 : // TODO: Switch this to (NodeId, shadowable = false);
260 : std::unordered_map<std::string, Definition> values;
261 : };
262 :
263 : } // namespace Resolver2_0
264 : } // namespace Rust
265 :
266 : #endif // !RUST_RIB_H
|