Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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 : : #include "rust-toplevel-name-resolver-2.0.h"
20 : : #include "optional.h"
21 : : #include "rust-ast-full.h"
22 : : #include "rust-hir-map.h"
23 : : #include "rust-attribute-values.h"
24 : :
25 : : namespace Rust {
26 : : namespace Resolver2_0 {
27 : :
28 : 21 : TopLevel::TopLevel (NameResolutionContext &resolver)
29 : 21 : : DefaultResolver (resolver)
30 : 21 : {}
31 : :
32 : : template <typename T>
33 : : void
34 : 41 : TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
35 : : Namespace ns)
36 : : {
37 : 41 : insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns);
38 : 41 : }
39 : :
40 : : void
41 : 41 : TopLevel::insert_or_error_out (const Identifier &identifier,
42 : : const location_t &locus, const NodeId &node_id,
43 : : Namespace ns)
44 : : {
45 : : // keep track of each node's location to provide useful errors
46 : 41 : node_locations.emplace (node_id, locus);
47 : :
48 : 41 : auto result = ctx.insert (identifier, node_id, ns);
49 : :
50 : 41 : if (!result)
51 : : {
52 : : // can we do something like check if the node id is the same? if it is the
53 : : // same, it's not an error, just the resolver running multiple times?
54 : :
55 : 0 : rich_location rich_loc (line_table, locus);
56 : 0 : rich_loc.add_range (node_locations[result.error ().existing]);
57 : :
58 : 0 : rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times",
59 : 0 : identifier.as_string ().c_str ());
60 : 0 : }
61 : 41 : }
62 : :
63 : : void
64 : 21 : TopLevel::go (AST::Crate &crate)
65 : : {
66 : : // we do not include builtin types in the top-level definition collector, as
67 : : // they are not used until `Late`. furthermore, we run this visitor multiple
68 : : // times in a row in a fixed-point fashion, so it would make the code
69 : : // responsible for this ugly and perfom a lot of error checking.
70 : :
71 : 74 : for (auto &item : crate.items)
72 : 53 : item->accept_vis (*this);
73 : 21 : }
74 : :
75 : : void
76 : 31 : TopLevel::visit (AST::Module &module)
77 : : {
78 : : // FIXME: Do we need to insert the module in the type namespace?
79 : :
80 : 62 : auto sub_visitor = [this, &module] () {
81 : 66 : for (auto &item : module.get_items ())
82 : 35 : item->accept_vis (*this);
83 : 62 : };
84 : :
85 : 93 : ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor,
86 : 31 : module.get_name ());
87 : 31 : }
88 : :
89 : : template <typename PROC_MACRO>
90 : : static void
91 : 0 : insert_macros (std::vector<PROC_MACRO> ¯os, NameResolutionContext &ctx)
92 : : {
93 : 0 : for (auto ¯o : macros)
94 : : {
95 : 0 : auto res = ctx.macros.insert (macro.get_name (), macro.get_node_id ());
96 : :
97 : 0 : if (!res)
98 : : {
99 : 0 : rust_error_at (UNKNOWN_LOCATION, ErrorCode::E0428,
100 : : "macro %qs defined multiple times",
101 : 0 : macro.get_name ().c_str ());
102 : : }
103 : : }
104 : 0 : }
105 : :
106 : : void
107 : 0 : TopLevel::visit (AST::ExternCrate &crate)
108 : : {
109 : 0 : CrateNum num;
110 : 0 : rust_assert (Analysis::Mappings::get ()->lookup_crate_name (
111 : : crate.get_referenced_crate (), num));
112 : :
113 : 0 : auto attribute_macros
114 : 0 : = Analysis::Mappings::get ()->lookup_attribute_proc_macros (num);
115 : :
116 : 0 : auto bang_macros = Analysis::Mappings::get ()->lookup_bang_proc_macros (num);
117 : :
118 : 0 : auto derive_macros
119 : 0 : = Analysis::Mappings::get ()->lookup_derive_proc_macros (num);
120 : :
121 : 0 : auto sub_visitor = [&] () {
122 : : // TODO: Find a way to keep this part clean without the double dispatch.
123 : 0 : if (derive_macros.has_value ())
124 : : {
125 : 0 : insert_macros (derive_macros.value (), ctx);
126 : 0 : for (auto ¯o : derive_macros.value ())
127 : 0 : Analysis::Mappings::get ()->insert_derive_proc_macro_def (macro);
128 : : }
129 : 0 : if (attribute_macros.has_value ())
130 : : {
131 : 0 : insert_macros (attribute_macros.value (), ctx);
132 : 0 : for (auto ¯o : attribute_macros.value ())
133 : 0 : Analysis::Mappings::get ()->insert_attribute_proc_macro_def (macro);
134 : : }
135 : 0 : if (bang_macros.has_value ())
136 : : {
137 : 0 : insert_macros (bang_macros.value (), ctx);
138 : 0 : for (auto ¯o : bang_macros.value ())
139 : 0 : Analysis::Mappings::get ()->insert_bang_proc_macro_def (macro);
140 : : }
141 : 0 : };
142 : :
143 : 0 : if (crate.has_as_clause ())
144 : 0 : ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor,
145 : 0 : crate.get_as_clause ());
146 : : else
147 : 0 : ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor,
148 : 0 : crate.get_referenced_crate ());
149 : 0 : }
150 : :
151 : : static bool
152 : 14 : is_macro_export (AST::MacroRulesDefinition &def)
153 : : {
154 : 14 : for (const auto &attr : def.get_outer_attrs ())
155 : 4 : if (attr.get_path ().as_string () == Values::Attributes::MACRO_EXPORT)
156 : 14 : return true;
157 : :
158 : : return false;
159 : : }
160 : :
161 : : void
162 : 14 : TopLevel::visit (AST::MacroRulesDefinition ¯o)
163 : : {
164 : : // we do not insert macros in the current rib as that needs to be done in the
165 : : // textual scope of the Early pass. we only insert them in the root of the
166 : : // crate if they are marked with #[macro_export]. The execption to this is
167 : : // macros 2.0, which get resolved and inserted like regular items.
168 : :
169 : 14 : if (is_macro_export (macro))
170 : : {
171 : 12 : auto res = ctx.macros.insert_at_root (macro.get_rule_name (),
172 : 4 : macro.get_node_id ());
173 : 4 : if (!res)
174 : : {
175 : : // TODO: Factor this
176 : 0 : rich_location rich_loc (line_table, macro.get_locus ());
177 : 0 : rich_loc.add_range (node_locations[res.error ().existing]);
178 : :
179 : 0 : rust_error_at (rich_loc, ErrorCode::E0428,
180 : : "macro %qs defined multiple times",
181 : 0 : macro.get_rule_name ().as_string ().c_str ());
182 : 0 : }
183 : 4 : }
184 : :
185 : 14 : if (macro.get_kind () == AST::MacroRulesDefinition::MacroKind::DeclMacro)
186 : 2 : insert_or_error_out (macro.get_rule_name (), macro, Namespace::Macros);
187 : :
188 : 14 : auto mappings = Analysis::Mappings::get ();
189 : 14 : AST::MacroRulesDefinition *tmp = nullptr;
190 : 14 : if (mappings->lookup_macro_def (macro.get_node_id (), &tmp))
191 : 7 : return;
192 : :
193 : 7 : mappings->insert_macro_def (¯o);
194 : : }
195 : :
196 : : void
197 : 39 : TopLevel::visit (AST::Function &function)
198 : : {
199 : 39 : insert_or_error_out (function.get_function_name (), function,
200 : : Namespace::Values);
201 : :
202 : 39 : DefaultResolver::visit (function);
203 : 39 : }
204 : :
205 : : void
206 : 39 : TopLevel::visit (AST::BlockExpr &expr)
207 : : {
208 : : // extracting the lambda from the `scoped` call otherwise the code looks like
209 : : // a hot turd thanks to our .clang-format
210 : :
211 : 78 : auto sub_vis = [this, &expr] () {
212 : 95 : for (auto &stmt : expr.get_statements ())
213 : 56 : stmt->accept_vis (*this);
214 : :
215 : 39 : if (expr.has_tail_expr ())
216 : 14 : expr.get_tail_expr ()->accept_vis (*this);
217 : 78 : };
218 : :
219 : 39 : ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), sub_vis);
220 : 39 : }
221 : :
222 : : void
223 : 0 : TopLevel::visit (AST::StaticItem &static_item)
224 : : {
225 : 0 : auto sub_vis
226 : 0 : = [this, &static_item] () { static_item.get_expr ()->accept_vis (*this); };
227 : :
228 : 0 : ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis);
229 : 0 : }
230 : :
231 : : void
232 : 0 : TopLevel::visit (AST::StructStruct &struct_item)
233 : : {
234 : 0 : insert_or_error_out (struct_item.get_struct_name (), struct_item,
235 : : Namespace::Types);
236 : :
237 : : // Do we need to insert the constructor in the value namespace as well?
238 : :
239 : : // Do we need to do anything if the struct is a unit struct?
240 : 0 : if (struct_item.is_unit_struct ())
241 : 0 : insert_or_error_out (struct_item.get_struct_name (), struct_item,
242 : : Namespace::Values);
243 : 0 : }
244 : :
245 : : void
246 : 0 : TopLevel::visit (AST::TupleStruct &tuple_struct)
247 : : {
248 : 0 : insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct,
249 : : Namespace::Types);
250 : 0 : }
251 : :
252 : : void
253 : 0 : TopLevel::visit (AST::EnumItem &variant)
254 : : {
255 : 0 : insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
256 : 0 : }
257 : :
258 : : void
259 : 0 : TopLevel::visit (AST::EnumItemTuple &variant)
260 : : {
261 : 0 : insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
262 : 0 : }
263 : :
264 : : void
265 : 0 : TopLevel::visit (AST::EnumItemStruct &variant)
266 : : {
267 : 0 : insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
268 : 0 : }
269 : :
270 : : void
271 : 0 : TopLevel::visit (AST::EnumItemDiscriminant &variant)
272 : : {
273 : 0 : insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
274 : 0 : }
275 : :
276 : : void
277 : 0 : TopLevel::visit (AST::Enum &enum_item)
278 : : {
279 : 0 : insert_or_error_out (enum_item.get_identifier (), enum_item,
280 : : Namespace::Types);
281 : :
282 : 0 : auto field_vis = [this, &enum_item] () {
283 : 0 : for (auto &variant : enum_item.get_variants ())
284 : 0 : variant->accept_vis (*this);
285 : 0 : };
286 : :
287 : 0 : ctx.scoped (Rib::Kind::Item /* FIXME: Is that correct? */,
288 : 0 : enum_item.get_node_id (), field_vis, enum_item.get_identifier ());
289 : 0 : }
290 : :
291 : : void
292 : 0 : TopLevel::visit (AST::Union &union_item)
293 : : {
294 : 0 : insert_or_error_out (union_item.get_identifier (), union_item,
295 : : Namespace::Types);
296 : 0 : }
297 : :
298 : : void
299 : 8 : TopLevel::visit (AST::ConstantItem &const_item)
300 : : {
301 : 8 : auto expr_vis
302 : 8 : = [this, &const_item] () { const_item.get_expr ()->accept_vis (*this); };
303 : :
304 : 8 : ctx.scoped (Rib::Kind::ConstantItem, const_item.get_node_id (), expr_vis);
305 : 8 : }
306 : :
307 : : bool
308 : 0 : TopLevel::handle_use_dec (AST::SimplePath path)
309 : : {
310 : : // TODO: Glob imports can get shadowed by regular imports and regular items.
311 : : // So we need to store them in a specific way in the ForeverStack - which can
312 : : // also probably be used by labels and macros etc. Like store it as a
313 : : // `Shadowable(NodeId)` instead of just a `NodeId`
314 : :
315 : 0 : auto locus = path.get_final_segment ().get_locus ();
316 : 0 : auto declared_name = path.get_final_segment ().as_string ();
317 : :
318 : : // in what namespace do we perform path resolution? All of them? see which one
319 : : // matches? Error out on ambiguities?
320 : : // so, apparently, for each one that matches, add it to the proper namespace
321 : : // :(
322 : :
323 : 0 : auto found = false;
324 : :
325 : 0 : auto resolve_and_insert = [this, &found, &declared_name,
326 : : locus] (Namespace ns,
327 : : const AST::SimplePath &path) {
328 : 0 : tl::optional<NodeId> resolved = tl::nullopt;
329 : :
330 : : // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so
331 : : // that we can improve it with hints or location or w/ever. and maybe
332 : : // only emit it the first time.
333 : 0 : switch (ns)
334 : : {
335 : 0 : case Namespace::Values:
336 : 0 : resolved = ctx.values.resolve_path (path.get_segments ());
337 : 0 : break;
338 : 0 : case Namespace::Types:
339 : 0 : resolved = ctx.types.resolve_path (path.get_segments ());
340 : 0 : break;
341 : 0 : case Namespace::Macros:
342 : 0 : resolved = ctx.macros.resolve_path (path.get_segments ());
343 : 0 : break;
344 : 0 : case Namespace::Labels:
345 : : // TODO: Is that okay?
346 : 0 : rust_unreachable ();
347 : : }
348 : :
349 : : // FIXME: Ugly
350 : 0 : (void) resolved.map ([this, &found, &declared_name, locus, ns] (NodeId id) {
351 : 0 : found = true;
352 : :
353 : : // what do we do with the id?
354 : 0 : insert_or_error_out (declared_name, locus, id, ns);
355 : :
356 : 0 : return id;
357 : : });
358 : 0 : };
359 : :
360 : : // do this for all namespaces (even Labels?)
361 : :
362 : 0 : resolve_and_insert (Namespace::Values, path);
363 : 0 : resolve_and_insert (Namespace::Types, path);
364 : 0 : resolve_and_insert (Namespace::Macros, path);
365 : :
366 : : // TODO: No labels? No, right?
367 : :
368 : 0 : return found;
369 : 0 : }
370 : :
371 : : static void
372 : : flatten_rebind (const AST::UseTreeRebind &glob,
373 : : std::vector<AST::SimplePath> &paths);
374 : : static void
375 : : flatten_list (const AST::UseTreeList &glob,
376 : : std::vector<AST::SimplePath> &paths);
377 : : static void
378 : : flatten_glob (const AST::UseTreeGlob &glob,
379 : : std::vector<AST::SimplePath> &paths);
380 : :
381 : : static void
382 : 0 : flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
383 : : {
384 : 0 : switch (tree->get_kind ())
385 : : {
386 : 0 : case AST::UseTree::Rebind: {
387 : 0 : auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
388 : 0 : flatten_rebind (*rebind, paths);
389 : 0 : break;
390 : : }
391 : 0 : case AST::UseTree::List: {
392 : 0 : auto list = static_cast<const AST::UseTreeList *> (tree);
393 : 0 : flatten_list (*list, paths);
394 : 0 : break;
395 : : }
396 : 0 : case AST::UseTree::Glob: {
397 : 0 : rust_sorry_at (tree->get_locus (), "cannot resolve glob imports yet");
398 : 0 : auto glob = static_cast<const AST::UseTreeGlob *> (tree);
399 : 0 : flatten_glob (*glob, paths);
400 : 0 : break;
401 : : }
402 : : break;
403 : : }
404 : 0 : }
405 : :
406 : : static void
407 : 0 : flatten_rebind (const AST::UseTreeRebind &rebind,
408 : : std::vector<AST::SimplePath> &paths)
409 : : {
410 : 0 : auto path = rebind.get_path ();
411 : :
412 : : // FIXME: Do we want to emplace the rebind here as well?
413 : 0 : if (rebind.has_identifier ())
414 : : {
415 : 0 : auto rebind_path = path;
416 : 0 : auto new_seg = rebind.get_identifier ();
417 : :
418 : : // Add the identifier as a new path
419 : 0 : rebind_path.get_segments ().back ()
420 : 0 : = AST::SimplePathSegment (new_seg.as_string (), UNDEF_LOCATION);
421 : :
422 : 0 : paths.emplace_back (rebind_path);
423 : 0 : }
424 : : else
425 : : {
426 : 0 : paths.emplace_back (path);
427 : : }
428 : 0 : }
429 : :
430 : : static void
431 : 0 : flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
432 : : {
433 : 0 : auto prefix = AST::SimplePath::create_empty ();
434 : 0 : if (list.has_path ())
435 : 0 : prefix = list.get_path ();
436 : :
437 : 0 : for (const auto &tree : list.get_trees ())
438 : : {
439 : 0 : auto sub_paths = std::vector<AST::SimplePath> ();
440 : 0 : flatten (tree.get (), sub_paths);
441 : :
442 : 0 : for (auto &sub_path : sub_paths)
443 : : {
444 : 0 : auto new_path = prefix;
445 : 0 : std::copy (sub_path.get_segments ().begin (),
446 : 0 : sub_path.get_segments ().end (),
447 : : std::back_inserter (new_path.get_segments ()));
448 : :
449 : 0 : paths.emplace_back (new_path);
450 : 0 : }
451 : 0 : }
452 : 0 : }
453 : :
454 : : static void
455 : 0 : flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
456 : : {
457 : 0 : if (glob.has_path ())
458 : 0 : paths.emplace_back (glob.get_path ());
459 : 0 : }
460 : :
461 : : void
462 : 0 : TopLevel::visit (AST::UseDeclaration &use)
463 : : {
464 : 0 : auto paths = std::vector<AST::SimplePath> ();
465 : :
466 : : // FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup?
467 : : // How do we handle module imports in general? Should they get added to all
468 : : // namespaces?
469 : :
470 : 0 : const auto &tree = use.get_tree ();
471 : 0 : flatten (tree.get (), paths);
472 : :
473 : 0 : for (auto &path : paths)
474 : 0 : if (!handle_use_dec (path))
475 : 0 : rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433,
476 : : "could not resolve import %qs",
477 : 0 : path.as_string ().c_str ());
478 : 0 : }
479 : :
480 : : } // namespace Resolver2_0
481 : : } // namespace Rust
|