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_EARLY_NAME_RESOLVER_2_0_H
20 : #define RUST_EARLY_NAME_RESOLVER_2_0_H
21 :
22 : #include "optional.h"
23 : #include "rust-ast.h"
24 : #include "rust-ast-visitor.h"
25 : #include "rust-name-resolution-context.h"
26 : #include "rust-default-resolver.h"
27 : #include "rust-rib.h"
28 : #include "rust-toplevel-name-resolver-2.0.h"
29 :
30 : namespace Rust {
31 : namespace Resolver2_0 {
32 :
33 : class Early : public DefaultResolver
34 : {
35 : using DefaultResolver::visit;
36 :
37 : TopLevel toplevel;
38 : bool dirty;
39 :
40 : public:
41 : Early (NameResolutionContext &ctx);
42 :
43 8461 : bool is_dirty () { return dirty; }
44 :
45 : void go (AST::Crate &crate);
46 :
47 10411 : const std::vector<Error> &get_macro_resolve_errors () const
48 : {
49 10411 : return macro_resolve_errors;
50 : }
51 :
52 : // we need to handle definitions for textual scoping
53 : void visit (AST::MacroRulesDefinition &) override;
54 :
55 : // as well as lexical scopes
56 : void visit (AST::BlockExpr &) override;
57 : void visit (AST::Module &) override;
58 :
59 : void visit (AST::MacroInvocation &) override;
60 :
61 : void visit (AST::Function &) override;
62 : void visit (AST::StructStruct &) override;
63 : void visit (AST::UseDeclaration &) override;
64 : void visit (AST::UseTreeList &) override;
65 :
66 6098 : struct ImportData
67 : {
68 : enum class Kind
69 : {
70 : Simple,
71 : Glob,
72 : Rebind
73 : } kind;
74 :
75 : static ImportData
76 0 : Simple (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
77 : {
78 0 : return ImportData (Kind::Simple, std::move (definitions));
79 : }
80 :
81 : static ImportData
82 3041 : Rebind (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
83 : {
84 3041 : return ImportData (Kind::Rebind, std::move (definitions));
85 : }
86 :
87 16 : static ImportData Glob (Rib::Definition container)
88 : {
89 32 : return ImportData (Kind::Glob, container);
90 : }
91 :
92 17 : Rib::Definition container () const
93 : {
94 17 : rust_assert (kind == Kind::Glob);
95 17 : return glob_container;
96 : }
97 :
98 3037 : std::vector<std::pair<Rib::Definition, Namespace>> definitions () const
99 : {
100 3037 : rust_assert (kind != Kind::Glob);
101 3037 : return std::move (resolved_definitions);
102 : }
103 :
104 : private:
105 3041 : ImportData (
106 : Kind kind,
107 : std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
108 3041 : : kind (kind), resolved_definitions (std::move (definitions))
109 : {}
110 :
111 16 : ImportData (Kind kind, Rib::Definition container)
112 16 : : kind (kind), glob_container (container)
113 : {}
114 :
115 : // TODO: Should this be a union?
116 :
117 : // For Simple and Rebind
118 : std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions;
119 :
120 : // For Glob
121 : Rib::Definition glob_container;
122 : };
123 :
124 : struct ImportPair
125 : {
126 : TopLevel::ImportKind import_kind;
127 : ImportData data;
128 :
129 3057 : explicit ImportPair (TopLevel::ImportKind &&kind, ImportData &&data)
130 3057 : : import_kind (std::move (kind)), data (std::move (data))
131 : {}
132 : };
133 :
134 10411 : class ImportMappings
135 : {
136 : public:
137 3041 : std::vector<ImportPair> &new_or_access (NodeId path_id)
138 : {
139 : // We insert an empty vector, unless an element was already present for
140 : // `use_dec_id` - which is returned in the tuple's first member
141 3041 : auto iter = mappings.insert ({{path_id}, {}});
142 :
143 : // We then get that tuple's first member, which will be an iterator to the
144 : // existing vec<pair<ImportKind, ImportData>> OR an iterator to our newly
145 : // created empty vector (plus its key since this is a hashmap iterator).
146 : // we then access the second member of the pair to get access to the
147 : // vector directly.
148 3041 : return iter.first->second;
149 : }
150 :
151 : void insert (NodeId path_id, std::vector<ImportPair> &&pairs)
152 : {
153 : mappings.insert ({{path_id}, std::move (pairs)});
154 : }
155 :
156 : // Same as `insert`, but with just one node
157 16 : void insert (NodeId path_id, ImportPair &&pair)
158 : {
159 32 : mappings.insert ({{path_id}, {pair}});
160 16 : }
161 :
162 1842 : std::vector<ImportPair> &get (NodeId use_id) { return mappings[use_id]; }
163 :
164 : private:
165 : // Each path can import in multiple namespaces, hence the mapping from one
166 : // path to a vector of import pairs
167 : std::unordered_map<NodeId, std::vector<ImportPair>> mappings;
168 : };
169 :
170 : private:
171 : void visit_attributes (std::vector<AST::Attribute> &attrs);
172 :
173 : /**
174 : * Insert a resolved macro invocation into the mappings once, meaning that we
175 : * can call this function each time the early name resolution pass is underway
176 : * and it will not trigger assertions for already resolved invocations.
177 : */
178 : // TODO: Rename
179 : void insert_once (AST::MacroInvocation &invocation, NodeId resolved);
180 : // TODO: Rename
181 : void insert_once (AST::MacroRulesDefinition &definition);
182 :
183 : /**
184 : * Macros can either be resolved through textual scoping or regular path
185 : * scoping - which this class represents. Textual scoping works similarly to a
186 : * "simple" name resolution algorith, with the addition of "shadowing". Each
187 : * time a new lexical scope is entered, we push a new map onto the stack, in
188 : * which newly defined macros are added. The latest defined macro is the one
189 : * that takes precedence. When resolving a macro invocation to its definition,
190 : * we walk up the stack and look for a definition in each of the map until we
191 : * find one. Otherwise, the macro invocation is unresolved, and goes through
192 : * regular path resolution.
193 : */
194 10411 : class TextualScope
195 : {
196 : public:
197 : void push ();
198 : void pop ();
199 :
200 : void insert (std::string name, NodeId id);
201 : tl::optional<NodeId> get (const std::string &name);
202 :
203 : private:
204 : std::vector<std::unordered_map<std::string, NodeId>> scopes;
205 : };
206 :
207 : // Mappings between an import and the definition it imports
208 : ImportMappings import_mappings;
209 :
210 : // FIXME: Documentation
211 : // Call this on all the paths of a UseDec - so each flattened path in a
212 : // UseTreeList for example
213 : // FIXME: Should that return `found`?
214 : bool resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
215 : bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
216 : bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
217 :
218 : template <typename P>
219 : std::vector<std::pair<Rib::Definition, Namespace>>
220 3052 : resolve_path_in_all_ns (const P &path)
221 : {
222 3052 : std::vector<std::pair<Rib::Definition, Namespace>> resolved;
223 :
224 : // Pair a definition with the namespace it was found in
225 12208 : auto pair_with_ns = [&] (Namespace ns) {
226 3105 : return [&, ns] (Rib::Definition def) {
227 3105 : auto pair = std::make_pair (def, ns);
228 3105 : return resolved.emplace_back (std::move (pair));
229 12261 : };
230 : };
231 :
232 3052 : std::vector<Error> value_errors;
233 3052 : std::vector<Error> type_errors;
234 3052 : std::vector<Error> macro_errors;
235 :
236 3052 : ctx.resolve_path (path, value_errors, Namespace::Values)
237 3110 : .map (pair_with_ns (Namespace::Values));
238 3052 : ctx.resolve_path (path, type_errors, Namespace::Types)
239 6085 : .map (pair_with_ns (Namespace::Types));
240 3052 : ctx.resolve_path (path, macro_errors, Namespace::Macros)
241 3080 : .map (pair_with_ns (Namespace::Macros));
242 :
243 2 : if (!value_errors.empty () && !type_errors.empty ()
244 3054 : && !macro_errors.empty ())
245 4 : for (auto &ent : value_errors)
246 4 : collect_error (std::move (ent));
247 :
248 3052 : return resolved;
249 3052 : }
250 :
251 : // Handle an import, resolving it to its definition and adding it to the list
252 : // of import mappings
253 : void build_import_mapping (
254 : std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import);
255 :
256 : TextualScope textual_scope;
257 : std::vector<Error> macro_resolve_errors;
258 :
259 241 : void collect_error (Error e) { macro_resolve_errors.push_back (e); }
260 :
261 : void finalize_simple_import (const Early::ImportPair &mapping);
262 :
263 : void finalize_glob_import (NameResolutionContext &ctx,
264 : const Early::ImportPair &mapping);
265 :
266 : void finalize_rebind_import (const Early::ImportPair &mapping);
267 : };
268 :
269 : } // namespace Resolver2_0
270 : } // namespace Rust
271 :
272 : #endif // ! RUST_EARLY_NAME_RESOLVER_2_0_H
|