Line data Source code
1 : /* General AST-related method implementations for Rust frontend.
2 : Copyright (C) 2009-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : #include "rust-path.h"
21 : #include "rust-system.h"
22 : #include "rust-ast-full.h"
23 : #include "rust-diagnostics.h"
24 : #include "rust-ast-visitor.h"
25 : #include "rust-macro.h"
26 : #include "rust-session-manager.h"
27 : #include "rust-lex.h"
28 : #include "rust-parse.h"
29 : #include "rust-operators.h"
30 :
31 : namespace Rust {
32 : namespace AST {
33 :
34 : std::string
35 0 : GenericArgs::as_string () const
36 : {
37 0 : std::string args;
38 :
39 : // lifetime args
40 0 : if (!lifetime_args.empty ())
41 : {
42 0 : auto i = lifetime_args.begin ();
43 0 : auto e = lifetime_args.end ();
44 :
45 0 : for (; i != e; i++)
46 : {
47 0 : args += (*i).as_string ();
48 0 : if (e != i + 1)
49 0 : args += ", ";
50 : }
51 : }
52 :
53 : // type args
54 0 : if (!generic_args.empty ())
55 : {
56 0 : auto i = generic_args.begin ();
57 0 : auto e = generic_args.end ();
58 :
59 0 : for (; i != e; i++)
60 : {
61 0 : args += (*i).as_string ();
62 0 : if (e != i + 1)
63 0 : args += ", ";
64 : }
65 : }
66 :
67 : // binding args
68 0 : if (!binding_args.empty ())
69 : {
70 0 : auto i = binding_args.begin ();
71 0 : auto e = binding_args.end ();
72 :
73 0 : for (; i != e; i++)
74 : {
75 0 : args += (*i).as_string ();
76 0 : if (e != i + 1)
77 0 : args += ", ";
78 : }
79 : }
80 :
81 0 : return args;
82 : }
83 :
84 : GenericArg
85 66 : GenericArg::disambiguate_to_const () const
86 : {
87 66 : rust_assert (get_kind () == Kind::Either);
88 :
89 : // FIXME: is it fine to have no outer attributes?
90 66 : return GenericArg::create_const (
91 66 : std::unique_ptr<Expr> (new IdentifierExpr (path, {}, locus)));
92 : }
93 :
94 : GenericArg
95 12398 : GenericArg::disambiguate_to_type () const
96 : {
97 12398 : rust_assert (get_kind () == Kind::Either);
98 :
99 12398 : auto segment = std::unique_ptr<TypePathSegment> (
100 24796 : new TypePathSegment (path.as_string (), false, locus));
101 12398 : auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
102 12398 : segments.emplace_back (std::move (segment));
103 :
104 12398 : return GenericArg::create_type (
105 12398 : std::unique_ptr<Type> (new TypePath (std::move (segments), locus)));
106 12398 : }
107 :
108 : std::string
109 0 : GenericArgsBinding::as_string () const
110 : {
111 0 : auto type_string = type->as_string ();
112 0 : auto separator = kind == Kind::Constraint ? " : " : " = ";
113 0 : return identifier.as_string () + separator + type_string;
114 0 : }
115 :
116 : std::string
117 0 : ConstGenericParam::as_string () const
118 : {
119 0 : std::string str ("ConstGenericParam: ");
120 0 : str += "const " + name.as_string () + ": " + type->as_string ();
121 :
122 0 : if (has_default_value ())
123 0 : str += " = " + get_default_value_unchecked ().as_string ();
124 :
125 0 : return str;
126 : }
127 :
128 : std::string
129 55846 : PathExprSegment::as_string () const
130 : {
131 : // TODO: rewrite dump to work with non-literalisable types
132 55846 : std::string ident_str = segment_name.as_string ();
133 55846 : if (has_generic_args ())
134 0 : ident_str += "::<" + generic_args.as_string () + ">";
135 :
136 55846 : return ident_str;
137 : }
138 :
139 : std::string
140 1 : Path::as_string () const
141 : {
142 : // FIXME: Impl for lang items
143 1 : rust_assert (kind == Kind::Regular);
144 :
145 1 : std::string str;
146 :
147 2 : for (const auto &segment : segments)
148 3 : str += segment.as_string () + "::";
149 :
150 : // basically a hack - remove last two characters of string (remove final ::)
151 1 : str.erase (str.length () - 2);
152 :
153 1 : return str;
154 : }
155 :
156 : SimplePath
157 55592 : Path::convert_to_simple_path (bool with_opening_scope_resolution) const
158 : {
159 55592 : rust_assert (kind == Kind::Regular);
160 :
161 55592 : if (!has_segments ())
162 0 : return SimplePath::create_empty ();
163 :
164 : // create vector of reserved size (to minimise reallocations)
165 55592 : std::vector<SimplePathSegment> simple_segments;
166 55592 : simple_segments.reserve (segments.size ());
167 :
168 111437 : for (const auto &segment : segments)
169 : {
170 : // return empty path if doesn't meet simple path segment requirements
171 55845 : if (segment.is_error () || segment.has_generic_args ())
172 0 : return SimplePath::create_empty ();
173 :
174 : // create segment and add to vector
175 55845 : std::string segment_str = segment.as_string ();
176 55845 : simple_segments.emplace_back (std::move (segment_str),
177 55845 : segment.get_locus ());
178 55845 : }
179 :
180 : // kind of a HACK to get locus depending on opening scope resolution
181 55592 : location_t locus = UNKNOWN_LOCATION;
182 55592 : if (with_opening_scope_resolution)
183 0 : locus = simple_segments[0].get_locus () - 2; // minus 2 chars for ::
184 : else
185 55592 : locus = simple_segments[0].get_locus ();
186 : // FIXME: this hack probably doesn't actually work
187 :
188 55592 : return SimplePath (std::move (simple_segments), with_opening_scope_resolution,
189 55592 : locus);
190 55592 : }
191 :
192 : void
193 19256570 : PathInExpression::accept_vis (ASTVisitor &vis)
194 : {
195 19256570 : vis.visit (*this);
196 19256569 : }
197 :
198 : std::string
199 1 : PathInExpression::as_string () const
200 : {
201 1 : std::string str;
202 :
203 1 : if (has_opening_scope_resolution)
204 0 : str = "::";
205 :
206 1 : return str + Path::as_string ();
207 1 : }
208 :
209 : std::string
210 0 : TypePathSegmentGeneric::as_string () const
211 : {
212 : // TODO: rewrite to work with non-linearisable types
213 0 : return TypePathSegment::as_string () + "<" + generic_args.as_string () + ">";
214 : }
215 :
216 : std::string
217 0 : TypePathSegmentFunction::as_string () const
218 : {
219 : // TODO: rewrite to work with non-linearisable types
220 0 : return TypePathSegment::as_string () + function_path.as_string ();
221 : }
222 :
223 : std::string
224 1578 : TypePath::as_string () const
225 : {
226 : /* TODO: this may need to be rewritten if a segment (e.g. function) can't be
227 : * literalised */
228 1578 : std::string str;
229 :
230 1578 : if (has_opening_scope_resolution)
231 0 : str = "::";
232 :
233 3156 : for (const auto &segment : segments)
234 4734 : str += segment->as_string () + "::";
235 :
236 : // kinda hack - remove last 2 '::' characters
237 1578 : str.erase (str.length () - 2);
238 :
239 1578 : return str;
240 : }
241 :
242 : SimplePath
243 498 : TypePath::as_simple_path () const
244 : {
245 498 : if (segments.empty ())
246 0 : return SimplePath::create_empty ();
247 :
248 : // create vector of reserved size (to minimise reallocations)
249 498 : std::vector<SimplePathSegment> simple_segments;
250 498 : simple_segments.reserve (segments.size ());
251 :
252 996 : for (const auto &segment : segments)
253 : {
254 : // return empty path if doesn't meet simple path segment requirements
255 498 : if (segment == nullptr || segment->is_error ()
256 996 : || !segment->is_ident_only () || segment->as_string () == "Self")
257 0 : return SimplePath::create_empty ();
258 :
259 : // create segment and add to vector
260 498 : std::string segment_str = segment->as_string ();
261 498 : simple_segments.emplace_back (std::move (segment_str),
262 498 : segment->get_locus ());
263 498 : }
264 :
265 498 : return SimplePath (std::move (simple_segments), has_opening_scope_resolution,
266 498 : locus);
267 498 : }
268 :
269 : std::string
270 27 : TypePath::make_debug_string () const
271 : {
272 27 : rust_assert (!segments.empty ());
273 :
274 27 : std::string output;
275 :
276 54 : for (const auto &segment : segments)
277 : {
278 27 : if (segment != nullptr && !segment->is_lang_item ()
279 54 : && !segment->is_error ())
280 : {
281 27 : if (!output.empty () || has_opening_scope_resolution_op ())
282 0 : output.append ("::");
283 81 : output.append (segment->get_ident_segment ().as_string ());
284 : }
285 : }
286 :
287 27 : return output;
288 : }
289 :
290 : // hopefully definition here will prevent circular dependency issue
291 : TraitBound *
292 3 : TypePath::to_trait_bound (bool in_parens) const
293 : {
294 : // If already in parentheses, don't convert to trait bound
295 : // This ensures (TypePath) stays as ParenthesisedType in the parser
296 3 : if (in_parens)
297 : return nullptr;
298 :
299 0 : return new TraitBound (TypePath (*this), get_locus (), in_parens);
300 : }
301 :
302 : std::string
303 0 : TypePathFunction::as_string () const
304 : {
305 : // TODO: rewrite to work with non-linearisable types
306 0 : std::string str ("(");
307 :
308 0 : if (has_inputs ())
309 : {
310 0 : auto i = inputs.begin ();
311 0 : auto e = inputs.end ();
312 :
313 0 : for (; i != e; i++)
314 : {
315 0 : str += (*i)->as_string ();
316 0 : if (e != i + 1)
317 0 : str += ", ";
318 : }
319 : }
320 :
321 0 : str += ")";
322 :
323 0 : if (has_return_type ())
324 0 : str += " -> " + return_type->as_string ();
325 :
326 0 : return str;
327 : }
328 :
329 : std::string
330 0 : QualifiedPathInExpression::as_string () const
331 : {
332 0 : return path_type.as_string () + "::" + Path::as_string ();
333 : }
334 :
335 : std::string
336 0 : QualifiedPathInType::as_string () const
337 : {
338 : /* TODO: this may need adjusting if segments (e.g. with functions) can't be
339 : * literalised */
340 0 : std::string str = path_type.as_string ();
341 :
342 0 : str += "::" + associated_segment->as_string ();
343 0 : for (const auto &segment : segments)
344 0 : str += "::" + segment->as_string ();
345 :
346 0 : return str;
347 : }
348 :
349 : void
350 19779 : ConstGenericParam::accept_vis (ASTVisitor &vis)
351 : {
352 19779 : vis.visit (*this);
353 19779 : }
354 :
355 : void
356 16569242 : TypePathSegment::accept_vis (ASTVisitor &vis)
357 : {
358 16569242 : vis.visit (*this);
359 16569242 : }
360 :
361 : void
362 3918308 : TypePathSegmentGeneric::accept_vis (ASTVisitor &vis)
363 : {
364 3918308 : vis.visit (*this);
365 3918308 : }
366 :
367 : void
368 137004 : TypePathSegmentFunction::accept_vis (ASTVisitor &vis)
369 : {
370 137004 : vis.visit (*this);
371 137004 : }
372 :
373 : void
374 15145591 : TypePath::accept_vis (ASTVisitor &vis)
375 : {
376 15145591 : vis.visit (*this);
377 15145591 : }
378 :
379 : void
380 33089 : QualifiedPathInExpression::accept_vis (ASTVisitor &vis)
381 : {
382 33089 : vis.visit (*this);
383 33089 : }
384 :
385 : void
386 751188 : QualifiedPathInType::accept_vis (ASTVisitor &vis)
387 : {
388 751188 : vis.visit (*this);
389 751188 : }
390 :
391 : } // namespace AST
392 : } // namespace Rust
|