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