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