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