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