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