]>
Commit | Line | Data |
---|---|---|
767698ff | 1 | // Copyright (C) 2020-2024 Free Software Foundation, Inc. |
8288dc0f AC |
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 | ||
f7d8356a AC |
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 | ||
8288dc0f AC |
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 | 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 | 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, | |
5a0e099e | 121 | } kind; |
8288dc0f AC |
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 | |
5a0e099e | 135 | * @param can_shadow If the newly inserted value can shadow an existing one |
8288dc0f AC |
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 | */ | |
5a0e099e AC |
141 | tl::expected<NodeId, DuplicateNameError> insert (std::string name, NodeId id, |
142 | bool can_shadow = false); | |
8288dc0f AC |
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: | |
8288dc0f AC |
155 | std::unordered_map<std::string, NodeId> values; |
156 | }; | |
157 | ||
158 | } // namespace Resolver2_0 | |
159 | } // namespace Rust | |
160 | ||
161 | #endif // !RUST_RIB_H |