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 34562 : BindingLayer::BindingLayer (BindingSource source) : source (source)
29 : {
30 34562 : push (Binding::Kind::Product);
31 34562 : }
32 :
33 : bool
34 49502 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
35 : {
36 99344 : for (auto &bind : bindings)
37 : {
38 49908 : if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
39 49908 : && bind.kind == kind)
40 : {
41 49502 : return true;
42 : }
43 : }
44 : return false;
45 : }
46 :
47 : void
48 35153 : BindingLayer::push (Binding::Kind kind)
49 : {
50 35153 : bindings.push_back (Binding (kind));
51 35153 : }
52 :
53 : bool
54 24755 : BindingLayer::is_and_bound (Identifier ident)
55 : {
56 24755 : return bind_test (ident, Binding::Kind::Product);
57 : }
58 :
59 : bool
60 24747 : BindingLayer::is_or_bound (Identifier ident)
61 : {
62 24747 : return bind_test (ident, Binding::Kind::Or);
63 : }
64 :
65 : void
66 24747 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
67 : bool is_mut)
68 : {
69 24747 : bindings.back ().idents.emplace (
70 24747 : std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
71 24747 : }
72 :
73 : void
74 591 : BindingLayer::merge ()
75 : {
76 591 : auto last_binding = std::move (bindings.back ());
77 591 : bindings.pop_back ();
78 :
79 591 : if (bindings.back ().has_expected_bindings)
80 : {
81 267 : for (auto &value : bindings.back ().idents)
82 : {
83 58 : auto ident = value.first;
84 58 : 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 58 : }
92 : }
93 :
94 765 : for (auto &value : last_binding.idents)
95 : {
96 174 : auto res = bindings.back ().idents.emplace (value);
97 174 : if (res.second)
98 : {
99 116 : 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 58 : auto this_mode = value.second.second;
111 58 : auto other_mode = res.first->second.second;
112 232 : 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 591 : if (bindings.back ().kind == Binding::Kind::Or)
125 400 : bindings.back ().has_expected_bindings = true;
126 591 : }
127 :
128 : BindingSource
129 8 : BindingLayer::get_source () const
130 : {
131 8 : return source;
132 : }
133 :
134 : Resolver::CanonicalPath
135 75766 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &,
136 : Namespace ns)
137 : {
138 151532 : auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
139 75766 : ret.set_crate_num (crate_num);
140 75766 : return ret;
141 : }
142 :
143 : Resolver::CanonicalPath
144 148957 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx,
145 : Namespace ns)
146 : {
147 148957 : auto parent_path = get_parent ().as_path (ctx, ns);
148 297914 : return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
149 148957 : }
150 :
151 : Resolver::CanonicalPath
152 27751 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx,
153 : Namespace ns)
154 : {
155 27751 : if (!cache)
156 : {
157 : // TODO: what namespace do we use here? can the caller give one?
158 17399 : auto res = ctx.lookup (lookup_id, ns).and_then ([&ctx] (NodeId id) {
159 9370 : return ctx.canonical_ctx.get_record_opt (id);
160 : });
161 :
162 17399 : if (!res)
163 : {
164 : // HACK: use a dummy value
165 : // this should bring us roughly to parity with nr1.0
166 : // since nr1.0 doesn't seem to handle canonical paths for generics
167 : // quite right anyways
168 24754 : return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
169 : }
170 :
171 5022 : cache = res.value ();
172 : }
173 15374 : return cache->as_path (ctx, ns);
174 : }
175 :
176 : Resolver::CanonicalPath
177 6943 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx,
178 : Namespace ns)
179 : {
180 6943 : auto parent_path = get_parent ().as_path (ctx, ns);
181 6943 : return parent_path.append (
182 13886 : Resolver::CanonicalPath::inherent_impl_seg (impl_id,
183 20829 : type_record.as_path (ctx, ns)));
184 6943 : }
185 :
186 : Resolver::CanonicalPath
187 10404 : CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx,
188 : Namespace ns)
189 : {
190 : // Maybe this doesn't need the namespace and will always be in the types NS?
191 10404 : auto parent_path = get_parent ().as_path (ctx, ns);
192 10404 : return parent_path.append (
193 20808 : Resolver::CanonicalPath::trait_impl_projection_seg (
194 20808 : impl_id, trait_path_record.as_path (ctx, ns),
195 31212 : type_record.as_path (ctx, ns)));
196 10404 : }
197 :
198 4771 : NameResolutionContext::NameResolutionContext ()
199 4771 : : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
200 4771 : {}
201 :
202 : tl::expected<NodeId, DuplicateNameError>
203 156936 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
204 : {
205 156936 : switch (ns)
206 : {
207 71817 : case Namespace::Values:
208 71817 : return values.insert (name, id);
209 84955 : case Namespace::Types:
210 84955 : return types.insert (name, id);
211 164 : case Namespace::Macros:
212 164 : return macros.insert (name, id);
213 0 : case Namespace::Labels:
214 0 : default:
215 : // return labels.insert (name, id);
216 0 : rust_unreachable ();
217 : }
218 : }
219 :
220 : tl::expected<NodeId, DuplicateNameError>
221 4348 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
222 : bool is_also_value)
223 : {
224 4348 : auto res = types.insert_variant (name, id);
225 4348 : if (res.has_value () && is_also_value)
226 1194 : res = values.insert_variant (name, id);
227 4348 : return res;
228 : }
229 :
230 : tl::expected<NodeId, DuplicateNameError>
231 0 : NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
232 : Namespace ns)
233 : {
234 0 : switch (ns)
235 : {
236 0 : case Namespace::Values:
237 0 : return values.insert_shadowable (name, id);
238 0 : case Namespace::Types:
239 0 : return types.insert_shadowable (name, id);
240 0 : case Namespace::Macros:
241 0 : return macros.insert_shadowable (name, id);
242 0 : case Namespace::Labels:
243 0 : default:
244 : // return labels.insert (name, id);
245 0 : rust_unreachable ();
246 : }
247 : }
248 :
249 : tl::expected<NodeId, DuplicateNameError>
250 84 : NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
251 : {
252 84 : switch (ns)
253 : {
254 42 : case Namespace::Values:
255 42 : return values.insert_globbed (name, id);
256 42 : case Namespace::Types:
257 42 : return types.insert_globbed (name, id);
258 0 : case Namespace::Macros:
259 0 : return macros.insert_globbed (name, id);
260 0 : case Namespace::Labels:
261 0 : default:
262 : // return labels.insert (name, id);
263 0 : rust_unreachable ();
264 : }
265 : }
266 :
267 : // TODO: Maybe this should take a NamespacedDefinition as argument?
268 : void
269 214779 : NameResolutionContext::map_usage (Usage usage, Definition definition,
270 : Namespace ns)
271 : {
272 214779 : switch (ns)
273 : {
274 76620 : case Namespace::Values:
275 76620 : values.map_usage (usage, definition);
276 76620 : break;
277 137757 : case Namespace::Types:
278 137757 : types.map_usage (usage, definition);
279 137757 : break;
280 25 : case Namespace::Labels:
281 25 : labels.map_usage (usage, definition);
282 25 : break;
283 377 : case Namespace::Macros:
284 377 : macros.map_usage (usage, definition);
285 377 : break;
286 : }
287 214779 : }
288 :
289 : tl::optional<NodeId>
290 3207152 : NameResolutionContext::lookup (NodeId usage, Namespace ns) const
291 : {
292 3207152 : switch (ns)
293 : {
294 311727 : case Namespace::Values:
295 311727 : return values.lookup (usage);
296 2895324 : case Namespace::Types:
297 2895324 : return types.lookup (usage);
298 101 : case Namespace::Labels:
299 101 : return labels.lookup (usage);
300 0 : case Namespace::Macros:
301 0 : return macros.lookup (usage);
302 0 : default:
303 0 : rust_unreachable ();
304 : }
305 : }
306 :
307 : tl::optional<NameResolutionContext::NSLookup>
308 190275 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2) const
309 : {
310 190275 : if (auto result = lookup (usage, ns1))
311 130710 : return NSLookup (*result, ns1);
312 :
313 59565 : return lookup (usage, ns2).map ([&ns2] (NodeId id) {
314 55699 : return NSLookup (id, ns2);
315 : });
316 : }
317 :
318 : tl::optional<NameResolutionContext::NSLookup>
319 0 : NameResolutionContext::lookup (NodeId usage, Namespace ns1, Namespace ns2,
320 : Namespace ns3) const
321 : {
322 0 : if (auto result = lookup (usage, ns1, ns2))
323 0 : return result;
324 :
325 0 : return lookup (usage, ns3).map ([&ns3] (NodeId id) {
326 0 : return NSLookup (id, ns3);
327 : });
328 : }
329 :
330 : void
331 540154 : NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
332 : std::function<void (void)> lambda,
333 : tl::optional<Identifier> path)
334 : {
335 : // NOTE: You must be at the root node when pushing the prelude rib.
336 540154 : values.push (rib_kind, id, path);
337 540154 : types.push (rib_kind, id, path);
338 540154 : macros.push (rib_kind, id, path);
339 : // labels.push (rib, id);
340 :
341 540154 : lambda ();
342 :
343 540146 : values.pop ();
344 540146 : types.pop ();
345 540146 : macros.pop ();
346 : // labels.pop (rib);
347 540146 : }
348 :
349 : void
350 0 : NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
351 : NodeId scope_id,
352 : std::function<void (void)> lambda,
353 : tl::optional<Identifier> path)
354 : {
355 : // This could work... I'm not sure why you would want to do this though.
356 0 : rust_assert (rib_kind != Rib::Kind::Prelude);
357 :
358 0 : switch (ns)
359 : {
360 0 : case Namespace::Values:
361 0 : values.push (rib_kind, scope_id, path);
362 0 : break;
363 0 : case Namespace::Types:
364 0 : types.push (rib_kind, scope_id, path);
365 0 : break;
366 0 : case Namespace::Labels:
367 0 : case Namespace::Macros:
368 0 : gcc_unreachable ();
369 : }
370 :
371 0 : lambda ();
372 :
373 0 : switch (ns)
374 : {
375 0 : case Namespace::Values:
376 0 : values.pop ();
377 0 : break;
378 0 : case Namespace::Types:
379 0 : types.pop ();
380 0 : break;
381 : case Namespace::Labels:
382 : case Namespace::Macros:
383 : gcc_unreachable ();
384 : }
385 0 : }
386 :
387 : #if 0
388 : void
389 : NameResolutionContext::flatten ()
390 : {
391 : values.flatten ();
392 : types.flatten ();
393 : macros.flatten ();
394 : labels.flatten ();
395 : }
396 : #endif
397 :
398 : } // namespace Resolver2_0
399 : } // namespace Rust
|