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 : #include "rust-name-resolution-context.h"
20 : #include "optional.h"
21 : #include "rust-mapping-common.h"
22 : #include "rust-rib.h"
23 : #include "rust-system.h"
24 :
25 : namespace Rust {
26 : namespace Resolver2_0 {
27 :
28 100296 : BindingLayer::BindingLayer (BindingSource source) : source (source)
29 : {
30 100296 : push (Binding::Kind::Product);
31 100296 : }
32 :
33 : bool
34 91752 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
35 : {
36 183850 : for (auto &bind : bindings)
37 : {
38 92165 : if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
39 92165 : && bind.kind == kind)
40 : {
41 91752 : return true;
42 : }
43 : }
44 : return false;
45 : }
46 :
47 : void
48 101027 : BindingLayer::push (Binding::Kind kind)
49 : {
50 101027 : bindings.push_back (Binding (kind));
51 101027 : }
52 :
53 : bool
54 45880 : BindingLayer::is_and_bound (Identifier ident)
55 : {
56 45880 : return bind_test (ident, Binding::Kind::Product);
57 : }
58 :
59 : bool
60 45872 : BindingLayer::is_or_bound (Identifier ident)
61 : {
62 45872 : return bind_test (ident, Binding::Kind::Or);
63 : }
64 :
65 : void
66 45872 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
67 : bool is_mut)
68 : {
69 45872 : bindings.back ().idents.emplace (
70 45872 : std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
71 45872 : }
72 :
73 : void
74 731 : BindingLayer::merge ()
75 : {
76 731 : auto last_binding = std::move (bindings.back ());
77 731 : bindings.pop_back ();
78 :
79 731 : if (bindings.back ().has_expected_bindings)
80 : {
81 330 : for (auto &value : bindings.back ().idents)
82 : {
83 59 : auto ident = value.first;
84 59 : if (last_binding.idents.find (ident) == last_binding.idents.end ())
85 : {
86 0 : location_t locus = value.second.first;
87 0 : rust_error_at (locus, ErrorCode::E0408,
88 : "variable %qs is not bound in all patterns",
89 : ident.c_str ());
90 : }
91 59 : }
92 : }
93 :
94 908 : for (auto &value : last_binding.idents)
95 : {
96 177 : auto res = bindings.back ().idents.emplace (value);
97 177 : if (res.second)
98 : {
99 118 : if (bindings.back ().has_expected_bindings)
100 : {
101 14 : auto &ident = value.first;
102 14 : location_t locus = value.second.first;
103 14 : rust_error_at (locus, ErrorCode::E0408,
104 : "variable %qs is not bound in all patterns",
105 : ident.c_str ());
106 : }
107 : }
108 : else
109 : {
110 59 : auto this_mode = value.second.second;
111 59 : auto other_mode = res.first->second.second;
112 236 : if (this_mode != other_mode)
113 : {
114 7 : auto &ident = value.first;
115 7 : location_t locus = value.second.first;
116 7 : rust_error_at (locus, ErrorCode::E0409,
117 : "variable %qs is bound inconsistently across "
118 : "pattern alternatives",
119 : ident.c_str ());
120 : }
121 : }
122 : }
123 :
124 731 : if (bindings.back ().kind == Binding::Kind::Or)
125 501 : bindings.back ().has_expected_bindings = true;
126 731 : }
127 :
128 : BindingSource
129 8 : BindingLayer::get_source () const
130 : {
131 8 : return source;
132 : }
133 :
134 : Resolver::CanonicalPath
135 76829 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &,
136 : Namespace ns)
137 : {
138 153658 : auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
139 76829 : ret.set_crate_num (crate_num);
140 76829 : return ret;
141 : }
142 :
143 : Resolver::CanonicalPath
144 136838 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx,
145 : Namespace ns)
146 : {
147 136838 : auto &parent = ctx.canonical_ctx.get_record (get_parent ());
148 136838 : auto parent_path = parent.as_path (ctx, ns);
149 273676 : return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
150 136838 : }
151 :
152 : Resolver::CanonicalPath
153 28030 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx,
154 : Namespace ns)
155 : {
156 28030 : if (!cache)
157 : {
158 : // TODO: what namespace do we use here? can the caller give one?
159 17500 : auto res = ctx.lookup (lookup_id, ns).and_then ([&ctx] (NodeId id) {
160 9457 : return ctx.canonical_ctx.get_record_opt (id);
161 : });
162 :
163 17500 : if (!res)
164 : {
165 : // HACK: use a dummy value
166 : // this should bring us roughly to parity with nr1.0
167 : // since nr1.0 doesn't seem to handle canonical paths for generics
168 : // quite right anyways
169 12392 : return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
170 : }
171 :
172 5108 : cache = res.value ();
173 : }
174 15638 : return cache->as_path (ctx, ns);
175 : }
176 :
177 : Resolver::CanonicalPath
178 6976 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx,
179 : Namespace ns)
180 : {
181 6976 : auto parent_path
182 6976 : = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
183 6976 : return parent_path.append (
184 13952 : Resolver::CanonicalPath::inherent_impl_seg (impl_id,
185 20928 : type_record.as_path (ctx, ns)));
186 6976 : }
187 :
188 : Resolver::CanonicalPath
189 10527 : CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx,
190 : Namespace ns)
191 : {
192 : // Maybe this doesn't need the namespace and will always be in the types NS?
193 10527 : auto parent_path
194 10527 : = ctx.canonical_ctx.get_record (get_parent ()).as_path (ctx, ns);
195 10527 : return parent_path.append (
196 21054 : Resolver::CanonicalPath::trait_impl_projection_seg (
197 21054 : impl_id, trait_path_record.as_path (ctx, ns),
198 31581 : type_record.as_path (ctx, ns)));
199 10527 : }
200 :
201 4960 : NameResolutionContext::NameResolutionContext ()
202 4960 : : root (std::make_unique<Node> (Rib::Kind::Normal, UNKNOWN_NODEID)),
203 4960 : lang_prelude (
204 4960 : std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID, *root)),
205 4960 : extern_prelude (
206 4960 : std::make_unique<Node> (Rib::Kind::Prelude, UNKNOWN_NODEID)),
207 4960 : values (*root, *lang_prelude, *extern_prelude),
208 4960 : types (*root, *lang_prelude, *extern_prelude),
209 4960 : macros (*root, *lang_prelude, *extern_prelude),
210 4960 : labels (*root, *lang_prelude, *extern_prelude),
211 4960 : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
212 4960 : {}
213 :
214 : tl::expected<NodeId, DuplicateNameError>
215 1270040 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
216 : {
217 1270040 : switch (ns)
218 : {
219 548380 : case Namespace::Values:
220 548380 : return values.insert (name, id);
221 719606 : case Namespace::Types:
222 719606 : return types.insert (name, id);
223 2054 : case Namespace::Macros:
224 2054 : return macros.insert (name, id);
225 0 : case Namespace::Labels:
226 0 : default:
227 0 : return labels.insert (name, id);
228 : rust_unreachable ();
229 : }
230 : }
231 :
232 : tl::expected<NodeId, DuplicateNameError>
233 7621 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
234 : bool is_also_value)
235 : {
236 7621 : auto res = types.insert_variant (name, id);
237 7621 : if (res.has_value () && is_also_value)
238 1306 : res = values.insert_variant (name, id);
239 7621 : return res;
240 : }
241 :
242 : tl::expected<NodeId, DuplicateNameError>
243 0 : NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
244 : Namespace ns)
245 : {
246 0 : switch (ns)
247 : {
248 0 : case Namespace::Values:
249 0 : return values.insert_shadowable (name, id);
250 0 : case Namespace::Types:
251 0 : return types.insert_shadowable (name, id);
252 0 : case Namespace::Macros:
253 0 : return macros.insert_shadowable (name, id);
254 0 : case Namespace::Labels:
255 0 : return labels.insert (name, id);
256 0 : default:
257 0 : rust_unreachable ();
258 : }
259 : }
260 :
261 : tl::expected<NodeId, DuplicateNameError>
262 0 : NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
263 : {
264 0 : switch (ns)
265 : {
266 0 : case Namespace::Values:
267 0 : return values.insert_globbed (name, id);
268 0 : case Namespace::Types:
269 0 : return types.insert_globbed (name, id);
270 0 : case Namespace::Macros:
271 0 : return macros.insert_globbed (name, id);
272 0 : case Namespace::Labels:
273 0 : return labels.insert (name, id);
274 0 : default:
275 0 : rust_unreachable ();
276 : }
277 : }
278 :
279 : // TODO: Maybe this should take a NamespacedDefinition as argument?
280 : void
281 744607 : NameResolutionContext::map_usage (Usage usage, Definition definition,
282 : Namespace ns)
283 : {
284 744607 : switch (ns)
285 : {
286 356726 : case Namespace::Values:
287 356726 : values.map_usage (usage, definition);
288 356726 : break;
289 368288 : case Namespace::Types:
290 368288 : types.map_usage (usage, definition);
291 368288 : break;
292 46 : case Namespace::Labels:
293 46 : labels.map_usage (usage, definition);
294 46 : break;
295 19547 : case Namespace::Macros:
296 19547 : macros.map_usage (usage, definition);
297 19547 : break;
298 : }
299 744607 : }
300 :
301 : tl::optional<NodeId>
302 4739160 : NameResolutionContext::lookup (NodeId usage, Namespace ns) const
303 : {
304 4739160 : switch (ns)
305 : {
306 322398 : case Namespace::Values:
307 322398 : return values.lookup (usage);
308 4416617 : case Namespace::Types:
309 4416617 : return types.lookup (usage);
310 145 : case Namespace::Labels:
311 145 : return labels.lookup (usage);
312 0 : case Namespace::Macros:
313 0 : return macros.lookup (usage);
314 0 : default:
315 0 : rust_unreachable ();
316 : }
317 : }
318 :
319 : tl::optional<NameResolutionContext::NSLookup>
320 199274 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2) const
321 : {
322 199274 : if (auto result = lookup (usage, ns1))
323 134618 : return NSLookup (*result, ns1);
324 :
325 64656 : return lookup (usage, ns2).map ([&ns2] (NodeId id) {
326 60769 : return NSLookup (id, ns2);
327 : });
328 : }
329 :
330 : tl::optional<NameResolutionContext::NSLookup>
331 0 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2,
332 : Namespace ns3) const
333 : {
334 0 : if (auto result = lookup (usage, ns1, ns2))
335 0 : return result;
336 :
337 0 : return lookup (usage, ns3).map ([&ns3] (NodeId id) {
338 0 : return NSLookup (id, ns3);
339 : });
340 : }
341 :
342 : void
343 7691451 : NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
344 : std::function<void (void)> lambda,
345 : tl::optional<Identifier> path)
346 : {
347 : // NOTE: You must be at the root node when pushing the prelude rib.
348 7691451 : values.push (rib_kind, id, path);
349 7691451 : types.push (rib_kind, id, path);
350 7691451 : macros.push (rib_kind, id, path);
351 7691451 : labels.push (rib_kind, id, path);
352 :
353 7691451 : lambda ();
354 :
355 7691442 : values.pop ();
356 7691442 : types.pop ();
357 7691442 : macros.pop ();
358 7691442 : labels.pop ();
359 7691442 : }
360 :
361 : void
362 0 : NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
363 : NodeId scope_id,
364 : std::function<void (void)> lambda,
365 : tl::optional<Identifier> path)
366 : {
367 : // This could work... I'm not sure why you would want to do this though.
368 0 : rust_assert (rib_kind != Rib::Kind::Prelude);
369 :
370 0 : switch (ns)
371 : {
372 0 : case Namespace::Values:
373 0 : values.push (rib_kind, scope_id, path);
374 0 : break;
375 0 : case Namespace::Types:
376 0 : types.push (rib_kind, scope_id, path);
377 0 : break;
378 0 : case Namespace::Labels:
379 0 : labels.push (rib_kind, scope_id, path);
380 0 : break;
381 0 : case Namespace::Macros:
382 0 : gcc_unreachable ();
383 : }
384 :
385 0 : lambda ();
386 :
387 0 : switch (ns)
388 : {
389 0 : case Namespace::Values:
390 0 : values.pop ();
391 0 : break;
392 0 : case Namespace::Types:
393 0 : types.pop ();
394 0 : break;
395 0 : case Namespace::Labels:
396 0 : labels.pop ();
397 0 : break;
398 : case Namespace::Macros:
399 : gcc_unreachable ();
400 : }
401 0 : }
402 :
403 : void
404 48 : NameResolutionContext::merge (NameResolutionContext &other, NodeId at)
405 : {
406 : // TODO: merge once, for all namespaces at once
407 :
408 240 : auto merge_fstack = [&] (auto &stack, auto &other_stack, Namespace ns) {
409 192 : auto node = stack.dfs_node (stack.root, at);
410 192 : if (node)
411 : {
412 192 : auto &extern_crate_node = node.value ();
413 512 : for (auto kv : other_stack.root.children)
414 : {
415 160 : auto link = kv.first;
416 160 : auto child = kv.second;
417 320 : extern_crate_node.insert_child (link, child);
418 160 : child.parent = extern_crate_node;
419 : }
420 272 : for (auto kv : other_stack.root.rib (ns).get_values ())
421 : {
422 40 : auto name = kv.first;
423 40 : auto def = kv.second;
424 80 : extern_crate_node.rib (ns).insert (name, def);
425 : }
426 : }
427 192 : stack.resolved_nodes.insert (other_stack.resolved_nodes.begin (),
428 : other_stack.resolved_nodes.end ());
429 240 : };
430 :
431 48 : merge_fstack (values, other.values, Namespace::Values);
432 48 : merge_fstack (types, other.types, Namespace::Types);
433 48 : merge_fstack (macros, other.macros, Namespace::Macros);
434 48 : merge_fstack (labels, other.labels, Namespace::Labels);
435 48 : canonical_ctx.merge (std::move (other.canonical_ctx));
436 48 : }
437 :
438 : #if 0
439 : void
440 : NameResolutionContext::flatten ()
441 : {
442 : values.flatten ();
443 : types.flatten ();
444 : macros.flatten ();
445 : labels.flatten ();
446 : }
447 : #endif
448 :
449 : } // namespace Resolver2_0
450 : } // namespace Rust
|