Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : 38208 : 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 : 840059 : 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 : 26432 : Definition () = default;
136 : :
137 : 26213 : Definition &operator= (const Definition &) = default;
138 : 782393 : Definition (Definition const &) = default;
139 : :
140 : : bool is_variant () const;
141 : :
142 : : bool is_ambiguous () const;
143 : :
144 : 21715 : NodeId get_node_id () const
145 : : {
146 : 21715 : if (!ids_shadowable.empty ())
147 : 2200 : return ids_shadowable.back ();
148 : :
149 : 19515 : rust_assert (!is_ambiguous ());
150 : :
151 : 19515 : if (!ids_non_shadowable.empty ())
152 : 19511 : return ids_non_shadowable.back ();
153 : :
154 : 4 : rust_assert (!ids_globbed.empty ());
155 : 4 : 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 : : } kind;
192 : :
193 : 0 : static std::string kind_to_string (Rib::Kind kind)
194 : : {
195 : 0 : switch (kind)
196 : : {
197 : 0 : case Rib::Kind::Normal:
198 : 0 : return "Normal";
199 : 0 : case Rib::Kind::Module:
200 : 0 : return "Module";
201 : 0 : case Rib::Kind::Function:
202 : 0 : return "Function";
203 : 0 : case Rib::Kind::ConstantItem:
204 : 0 : return "ConstantItem";
205 : 0 : case Rib::Kind::TraitOrImpl:
206 : 0 : return "TraitOrImpl";
207 : 0 : case Rib::Kind::Item:
208 : 0 : return "Item";
209 : 0 : case Rib::Kind::Closure:
210 : 0 : return "Closure";
211 : 0 : case Rib::Kind::MacroDefinition:
212 : 0 : return "Macro definition";
213 : 0 : case Rib::Kind::ForwardTypeParamBan:
214 : 0 : return "Forward type param ban";
215 : 0 : case Rib::Kind::ConstParamType:
216 : 0 : return "Const Param Type";
217 : 0 : default:
218 : 0 : rust_unreachable ();
219 : : }
220 : : }
221 : :
222 : : Rib (Kind kind);
223 : : Rib (Kind kind, std::string identifier, NodeId id);
224 : : Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
225 : :
226 : : // TODO: What's the correctbehavior if the key already exists? What if a decl
227 : : // and use are in the same rib? Is that possible? Okay based on RibKind?
228 : :
229 : : /**
230 : : * Insert a new node in the rib
231 : : *
232 : : * @param name The name associated with the AST node
233 : : * @param def The `Definition` to insert
234 : : *
235 : : * @return `DuplicateNameError` if the node is already present in the rib. The
236 : : * `DuplicateNameError` class contains the NodeId of the existing
237 : : * node. Returns the new NodeId on success.
238 : : */
239 : : tl::expected<NodeId, DuplicateNameError> insert (std::string name,
240 : : Definition def);
241 : :
242 : : /**
243 : : * Access an inserted NodeId.
244 : : *
245 : : * @return tl::nullopt if the key does not exist, the NodeId otherwise
246 : : */
247 : : tl::optional<Rib::Definition> get (const std::string &name);
248 : :
249 : : /* View all the values stored in the rib */
250 : : const std::unordered_map<std::string, Definition> &get_values () const;
251 : :
252 : : private:
253 : : // TODO: Switch this to (NodeId, shadowable = false);
254 : : std::unordered_map<std::string, Definition> values;
255 : : };
256 : :
257 : : } // namespace Resolver2_0
258 : : } // namespace Rust
259 : :
260 : : #endif // !RUST_RIB_H
|