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