Line data Source code
1 : // Copyright (C) 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 "optional.h"
20 : #include "rust-name-resolution-context.h"
21 :
22 : /**
23 : * Split the actual path resolution logic in its own file because it's a lot,
24 : * and it could get even worse for certain edge cases.
25 : */
26 :
27 : namespace Rust {
28 : namespace Resolver2_0 {
29 :
30 : template <Namespace N>
31 : tl::optional<Rib::Definition>
32 91825 : NameResolutionContext::resolve_path (
33 : ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
34 : std::function<void (Usage, Definition)> insert_segment_resolution,
35 : std::vector<Error> &collect_errors)
36 : {
37 91825 : std::reference_wrapper<typename ForeverStack<N>::Node> starting_point
38 : = stack.cursor ();
39 :
40 91825 : return NameResolutionContext::resolve_path (stack, path, mode,
41 : insert_segment_resolution,
42 91825 : collect_errors, starting_point);
43 : }
44 :
45 : template <Namespace N>
46 : tl::optional<Rib::Definition>
47 0 : NameResolutionContext::resolve_path (
48 : ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
49 : std::function<void (Usage, Definition)> insert_segment_resolution,
50 : std::vector<Error> &collect_errors, NodeId starting_point_id)
51 :
52 : {
53 0 : auto starting_point = stack.dfs_node (stack.root, starting_point_id);
54 :
55 : // We may have a prelude, but haven't visited it yet and thus it's not in
56 : // our nodes
57 0 : if (!starting_point)
58 0 : return tl::nullopt;
59 :
60 0 : return NameResolutionContext::resolve_path (stack, path, mode,
61 : insert_segment_resolution,
62 0 : collect_errors, *starting_point);
63 : }
64 :
65 : template <Namespace N>
66 : tl::optional<Rib::Definition>
67 91825 : NameResolutionContext::resolve_path (
68 : ForeverStack<N> &stack, const ResolutionPath &path, ResolutionMode mode,
69 : std::function<void (Usage, Definition)> insert_segment_resolution,
70 : std::vector<Error> &collect_errors,
71 : std::reference_wrapper<typename ForeverStack<N>::Node> starting_point)
72 : {
73 91825 : bool can_descend = true;
74 :
75 91825 : rust_debug ("resolving %s", path.as_string ().c_str ());
76 :
77 91825 : if (auto lang_item = path.get_lang_prefix ())
78 : {
79 : NodeId seg_id
80 392 : = Analysis::Mappings::get ().get_lang_item_node (lang_item->first);
81 :
82 392 : insert_segment_resolution (Usage (lang_item->second),
83 392 : Definition (seg_id));
84 :
85 392 : if (path.get_segments ().empty ())
86 392 : return Rib::Definition::NonShadowable (seg_id);
87 :
88 0 : auto new_start = stack.dfs_node (stack.root, seg_id);
89 0 : rust_assert (new_start.has_value ());
90 0 : starting_point = new_start.value ();
91 :
92 0 : can_descend = false;
93 : }
94 : else
95 : {
96 91433 : switch (mode)
97 : {
98 : case ResolutionMode::Normal:
99 : break; // default
100 951 : case ResolutionMode::FromRoot:
101 951 : starting_point = stack.root;
102 951 : break;
103 0 : case ResolutionMode::FromExtern:
104 0 : starting_point = stack.extern_prelude;
105 0 : break;
106 0 : default:
107 0 : rust_unreachable ();
108 : }
109 : }
110 :
111 91433 : if (path.get_segments ().empty ())
112 1 : return Rib::Definition::NonShadowable (starting_point.get ().id);
113 :
114 91432 : auto &segments = path.get_segments ();
115 :
116 : // if there's only one segment, we just use `get`
117 182864 : if (can_descend && segments.size () == 1)
118 : {
119 71621 : auto &seg = segments.front ();
120 :
121 71621 : tl::optional<Rib::Definition> res
122 286484 : = stack.get (starting_point.get (), seg.name);
123 :
124 71621 : if (!res)
125 52337 : res = stack.get_lang_prelude (seg.name);
126 :
127 54535 : if (N == Namespace::Types && !res)
128 : {
129 200 : if (seg.is_crate_path_seg ())
130 : {
131 53 : insert_segment_resolution (Usage (seg.node_id),
132 53 : Definition (stack.root.id));
133 : // TODO: does NonShadowable matter?
134 53 : return Rib::Definition::NonShadowable (stack.root.id);
135 : }
136 147 : else if (seg.is_lower_self_seg ())
137 : {
138 5 : NodeId id = stack.find_closest_module (starting_point.get ()).id;
139 5 : insert_segment_resolution (Usage (seg.node_id), Definition (id));
140 : // TODO: does NonShadowable matter?
141 5 : return Rib::Definition::NonShadowable (id);
142 : }
143 142 : else if (seg.is_super_path_seg ())
144 : {
145 : auto &closest_module
146 1 : = stack.find_closest_module (starting_point.get ());
147 1 : if (closest_module.is_root ())
148 : {
149 0 : rust_error_at (seg.locus, ErrorCode::E0433,
150 : "too many leading %<super%> keywords");
151 0 : return tl::nullopt;
152 : }
153 :
154 1 : NodeId id
155 1 : = stack.find_closest_module (closest_module.parent.value ()).id;
156 1 : insert_segment_resolution (Usage (seg.node_id), Definition (id));
157 : // TODO: does NonShadowable matter?
158 1 : return Rib::Definition::NonShadowable (id);
159 : }
160 : else
161 : {
162 : // HACK: check for a module after we check the language prelude
163 628 : for (auto &kv :
164 141 : stack.find_closest_module (starting_point.get ()).children)
165 : {
166 496 : auto &link = kv.first;
167 :
168 992 : if (link.path.map_or (
169 1418 : [&seg] (Identifier path) {
170 426 : auto &path_str = path.as_string ();
171 426 : return path_str == seg.name;
172 : },
173 496 : false))
174 : {
175 9 : insert_segment_resolution (Usage (seg.node_id),
176 9 : Definition (kv.second.id));
177 9 : return Rib::Definition::NonShadowable (kv.second.id);
178 : }
179 : }
180 : }
181 : }
182 :
183 71553 : if (res && !res->is_ambiguous ())
184 70957 : insert_segment_resolution (Usage (seg.node_id),
185 70957 : Definition (res->get_node_id ()));
186 71553 : return res;
187 71621 : }
188 :
189 19811 : auto iterator = segments.begin ();
190 19811 : if (can_descend)
191 : {
192 19811 : if (auto res = stack.find_starting_point (segments, starting_point,
193 : insert_segment_resolution,
194 : collect_errors))
195 19809 : iterator = *res;
196 : else
197 2 : return tl::nullopt;
198 : }
199 :
200 : // We do the first part of path resolution exclusively in the types NS - this
201 : // gives us a node in which to resolve the last segment of the path.
202 :
203 : // We take our starting point and then get the equivalent Node from the Types
204 : // NS - since it existed in whatever namespace we are right now, we assume it
205 : // exists in the types NS.
206 : auto types_starting_point
207 19809 : = types.dfs_node (types.root, starting_point.get ().id);
208 :
209 : // TODO: Add a method for converting a node between namespaces? Make all of
210 : // the starting point stuff return a NodeId rather than a Node&? And take a
211 : // NodeId as a starting point rather than a Node?
212 :
213 : auto node
214 19809 : = types.resolve_segments (types_starting_point.value (), segments, iterator,
215 : insert_segment_resolution, collect_errors);
216 :
217 19809 : if (!node)
218 1846 : return tl::nullopt;
219 :
220 : // This node now represents the Node which *should* contain the definition
221 : // used by the last segment. We now get the equivalent Node from this
222 : // namespace after finding it in the types NS.
223 17963 : auto final_node_id = node.value ().id;
224 17963 : auto final_node = stack.dfs_node (stack.root, final_node_id).value ();
225 :
226 : // leave resolution within impl blocks to type checker
227 17963 : if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
228 0 : return tl::nullopt;
229 :
230 17963 : auto &seg = segments.back ();
231 22662 : std::string seg_name = seg.name;
232 :
233 17963 : tl::optional<Rib::Definition> res
234 : = stack.resolve_final_segment (final_node, seg_name,
235 17963 : seg.is_lower_self_seg ());
236 : // Ok we didn't find it in the rib, Lets try the prelude...
237 17963 : if (!res)
238 7722 : res = stack.get_lang_prelude (seg_name);
239 :
240 4699 : if (N == Namespace::Types && !res)
241 : {
242 : // HACK: check for a module after we check the language prelude
243 2339 : for (auto &kv : final_node.children)
244 : {
245 1338 : auto &link = kv.first;
246 :
247 2676 : if (link.path.map_or (
248 2770 : [&seg_name] (Identifier path) {
249 94 : auto &path_str = path.as_string ();
250 94 : return path_str == seg_name;
251 : },
252 1338 : false))
253 : {
254 59 : insert_segment_resolution (Usage (seg.node_id),
255 59 : Definition (kv.second.id));
256 59 : return Rib::Definition::NonShadowable (kv.second.id);
257 : }
258 : }
259 : }
260 :
261 17904 : if (res && !res->is_ambiguous ())
262 10239 : insert_segment_resolution (Usage (seg.node_id),
263 10239 : Definition (res->get_node_id ()));
264 :
265 17904 : return res;
266 17963 : }
267 :
268 : } // namespace Resolver2_0
269 : } // namespace Rust
|