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 :
23 : namespace Rust {
24 : namespace Resolver2_0 {
25 :
26 34046 : BindingLayer::BindingLayer (BindingSource source) : source (source)
27 : {
28 34046 : push (Binding::Kind::Product);
29 34046 : }
30 :
31 : bool
32 48892 : BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
33 : {
34 98124 : for (auto &bind : bindings)
35 : {
36 49298 : if (bind.idents.find (ident.as_string ()) != bind.idents.cend ()
37 49298 : && bind.kind == kind)
38 : {
39 48892 : return true;
40 : }
41 : }
42 : return false;
43 : }
44 :
45 : void
46 34637 : BindingLayer::push (Binding::Kind kind)
47 : {
48 34637 : bindings.push_back (Binding (kind));
49 34637 : }
50 :
51 : bool
52 24450 : BindingLayer::is_and_bound (Identifier ident)
53 : {
54 24450 : return bind_test (ident, Binding::Kind::Product);
55 : }
56 :
57 : bool
58 24442 : BindingLayer::is_or_bound (Identifier ident)
59 : {
60 24442 : return bind_test (ident, Binding::Kind::Or);
61 : }
62 :
63 : void
64 24442 : BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref,
65 : bool is_mut)
66 : {
67 24442 : bindings.back ().idents.emplace (
68 24442 : std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut)));
69 24442 : }
70 :
71 : void
72 591 : BindingLayer::merge ()
73 : {
74 591 : auto last_binding = std::move (bindings.back ());
75 591 : bindings.pop_back ();
76 :
77 591 : if (bindings.back ().has_expected_bindings)
78 : {
79 267 : for (auto &value : bindings.back ().idents)
80 : {
81 58 : auto ident = value.first;
82 58 : if (last_binding.idents.find (ident) == last_binding.idents.end ())
83 : {
84 0 : location_t locus = value.second.first;
85 0 : rust_error_at (locus, ErrorCode::E0408,
86 : "variable %qs is not bound in all patterns",
87 : ident.c_str ());
88 : }
89 58 : }
90 : }
91 :
92 765 : for (auto &value : last_binding.idents)
93 : {
94 174 : auto res = bindings.back ().idents.emplace (value);
95 174 : if (res.second)
96 : {
97 116 : if (bindings.back ().has_expected_bindings)
98 : {
99 14 : auto &ident = value.first;
100 14 : location_t locus = value.second.first;
101 14 : rust_error_at (locus, ErrorCode::E0408,
102 : "variable %qs is not bound in all patterns",
103 : ident.c_str ());
104 : }
105 : }
106 : else
107 : {
108 58 : auto this_mode = value.second.second;
109 58 : auto other_mode = res.first->second.second;
110 232 : if (this_mode != other_mode)
111 : {
112 7 : auto &ident = value.first;
113 7 : location_t locus = value.second.first;
114 7 : rust_error_at (locus, ErrorCode::E0409,
115 : "variable %qs is bound inconsistently across "
116 : "pattern alternatives",
117 : ident.c_str ());
118 : }
119 : }
120 : }
121 :
122 591 : if (bindings.back ().kind == Binding::Kind::Or)
123 400 : bindings.back ().has_expected_bindings = true;
124 591 : }
125 :
126 : BindingSource
127 8 : BindingLayer::get_source () const
128 : {
129 8 : return source;
130 : }
131 :
132 : Resolver::CanonicalPath
133 74890 : CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &)
134 : {
135 149780 : auto ret = Resolver::CanonicalPath::new_seg (node_id, seg);
136 74890 : ret.set_crate_num (crate_num);
137 74890 : return ret;
138 : }
139 :
140 : Resolver::CanonicalPath
141 147784 : CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx)
142 : {
143 147784 : auto parent_path = get_parent ().as_path (ctx);
144 295568 : return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg));
145 147784 : }
146 :
147 : Resolver::CanonicalPath
148 27380 : CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx)
149 : {
150 27380 : if (!cache)
151 : {
152 17168 : auto res = ctx.lookup (lookup_id).and_then (
153 33231 : [&ctx] (NodeId id) { return ctx.canonical_ctx.get_record_opt (id); });
154 :
155 17168 : if (!res)
156 : {
157 : // HACK: use a dummy value
158 : // this should bring us roughly to parity with nr1.0
159 : // since nr1.0 doesn't seem to handle canonical paths for generics
160 : // quite right anyways
161 12190 : return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX");
162 : }
163 :
164 4978 : cache = res.value ();
165 : }
166 15190 : return cache->as_path (ctx);
167 : }
168 :
169 : Resolver::CanonicalPath
170 6856 : CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx)
171 : {
172 6856 : auto parent_path = get_parent ().as_path (ctx);
173 6856 : return parent_path.append (
174 13712 : Resolver::CanonicalPath::inherent_impl_seg (impl_id,
175 20568 : type_record.as_path (ctx)));
176 6856 : }
177 :
178 : Resolver::CanonicalPath
179 10262 : CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx)
180 : {
181 10262 : auto parent_path = get_parent ().as_path (ctx);
182 10262 : return parent_path.append (
183 20524 : Resolver::CanonicalPath::trait_impl_projection_seg (
184 30786 : impl_id, trait_path_record.as_path (ctx), type_record.as_path (ctx)));
185 10262 : }
186 :
187 4684 : NameResolutionContext::NameResolutionContext ()
188 4684 : : mappings (Analysis::Mappings::get ()), canonical_ctx (*this)
189 4684 : {}
190 :
191 : tl::expected<NodeId, DuplicateNameError>
192 152392 : NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
193 : {
194 152392 : switch (ns)
195 : {
196 71205 : case Namespace::Values:
197 71205 : return values.insert (name, id);
198 81020 : case Namespace::Types:
199 81020 : return types.insert (name, id);
200 167 : case Namespace::Macros:
201 167 : return macros.insert (name, id);
202 0 : case Namespace::Labels:
203 0 : default:
204 : // return labels.insert (name, id);
205 0 : rust_unreachable ();
206 : }
207 : }
208 :
209 : tl::expected<NodeId, DuplicateNameError>
210 4324 : NameResolutionContext::insert_variant (Identifier name, NodeId id,
211 : bool is_also_value)
212 : {
213 4324 : auto res = types.insert_variant (name, id);
214 4324 : if (res.has_value () && is_also_value)
215 1186 : res = values.insert_variant (name, id);
216 4324 : return res;
217 : }
218 :
219 : tl::expected<NodeId, DuplicateNameError>
220 0 : NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
221 : Namespace ns)
222 : {
223 0 : switch (ns)
224 : {
225 0 : case Namespace::Values:
226 0 : return values.insert_shadowable (name, id);
227 0 : case Namespace::Types:
228 0 : return types.insert_shadowable (name, id);
229 0 : case Namespace::Macros:
230 0 : return macros.insert_shadowable (name, id);
231 0 : case Namespace::Labels:
232 0 : default:
233 : // return labels.insert (name, id);
234 0 : rust_unreachable ();
235 : }
236 : }
237 :
238 : tl::expected<NodeId, DuplicateNameError>
239 63 : NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
240 : {
241 63 : switch (ns)
242 : {
243 34 : case Namespace::Values:
244 34 : return values.insert_globbed (name, id);
245 29 : case Namespace::Types:
246 29 : return types.insert_globbed (name, id);
247 0 : case Namespace::Macros:
248 0 : return macros.insert_globbed (name, id);
249 0 : case Namespace::Labels:
250 0 : default:
251 : // return labels.insert (name, id);
252 0 : rust_unreachable ();
253 : }
254 : }
255 :
256 : void
257 203953 : NameResolutionContext::map_usage (Usage usage, Definition definition)
258 : {
259 203953 : auto inserted = resolved_nodes.emplace (usage, definition).second;
260 :
261 : // is that valid?
262 203953 : rust_assert (inserted);
263 203953 : }
264 :
265 : tl::optional<NodeId>
266 2616360 : NameResolutionContext::lookup (NodeId usage) const
267 : {
268 2616360 : auto it = resolved_nodes.find (Usage (usage));
269 :
270 2616360 : if (it == resolved_nodes.end ())
271 6101 : return tl::nullopt;
272 :
273 2610259 : return it->second.id;
274 : }
275 :
276 : void
277 532199 : NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
278 : std::function<void (void)> lambda,
279 : tl::optional<Identifier> path)
280 : {
281 : // NOTE: You must be at the root node when pushing the prelude rib.
282 532199 : values.push (rib_kind, id, path);
283 532199 : types.push (rib_kind, id, path);
284 532199 : macros.push (rib_kind, id, path);
285 : // labels.push (rib, id);
286 :
287 532199 : lambda ();
288 :
289 532197 : values.pop ();
290 532197 : types.pop ();
291 532197 : macros.pop ();
292 : // labels.pop (rib);
293 532197 : }
294 :
295 : void
296 0 : NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
297 : NodeId scope_id,
298 : std::function<void (void)> lambda,
299 : tl::optional<Identifier> path)
300 : {
301 : // This could work... I'm not sure why you would want to do this though.
302 0 : rust_assert (rib_kind != Rib::Kind::Prelude);
303 :
304 0 : switch (ns)
305 : {
306 0 : case Namespace::Values:
307 0 : values.push (rib_kind, scope_id, path);
308 0 : break;
309 0 : case Namespace::Types:
310 0 : types.push (rib_kind, scope_id, path);
311 0 : break;
312 0 : case Namespace::Labels:
313 0 : case Namespace::Macros:
314 0 : gcc_unreachable ();
315 : }
316 :
317 0 : lambda ();
318 :
319 0 : switch (ns)
320 : {
321 0 : case Namespace::Values:
322 0 : values.pop ();
323 0 : break;
324 0 : case Namespace::Types:
325 0 : types.pop ();
326 0 : break;
327 : case Namespace::Labels:
328 : case Namespace::Macros:
329 : gcc_unreachable ();
330 : }
331 0 : }
332 :
333 : } // namespace Resolver2_0
334 : } // namespace Rust
|