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 : auto i = lifetime_args.begin ();
43 : 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 : auto i = generic_args.begin ();
57 : 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 : auto i = binding_args.begin ();
71 : 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 31 : GenericArg::disambiguate_to_const () const
86 : {
87 31 : rust_assert (get_kind () == Kind::Either);
88 :
89 : // FIXME: is it fine to have no outer attributes?
90 31 : return GenericArg::create_const (
91 31 : std::unique_ptr<Expr> (new IdentifierExpr (path, {}, locus)));
92 : }
93 :
94 : GenericArg
95 2316 : GenericArg::disambiguate_to_type () const
96 : {
97 2316 : rust_assert (get_kind () == Kind::Either);
98 :
99 2316 : auto segment = std::unique_ptr<TypePathSegment> (
100 4632 : new TypePathSegment (path.as_string (), false, locus));
101 2316 : auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
102 2316 : segments.emplace_back (std::move (segment));
103 :
104 2316 : return GenericArg::create_type (
105 2316 : std::unique_ptr<Type> (new TypePath (std::move (segments), locus)));
106 2316 : }
107 :
108 : std::string
109 0 : GenericArgsBinding::as_string () const
110 : {
111 : // TODO: rewrite to work with non-literalisable types
112 0 : return identifier.as_string () + " = " + type->as_string ();
113 : }
114 :
115 : std::string
116 0 : ConstGenericParam::as_string () const
117 : {
118 0 : std::string str ("ConstGenericParam: ");
119 0 : str += "const " + name.as_string () + ": " + type->as_string ();
120 :
121 0 : if (has_default_value ())
122 0 : str += " = " + get_default_value_unchecked ().as_string ();
123 :
124 0 : return str;
125 : }
126 :
127 : std::string
128 2484 : PathExprSegment::as_string () const
129 : {
130 : // TODO: rewrite dump to work with non-literalisable types
131 2484 : std::string ident_str = segment_name.as_string ();
132 2484 : if (has_generic_args ())
133 0 : ident_str += "::<" + generic_args.as_string () + ">";
134 :
135 2484 : return ident_str;
136 : }
137 :
138 : std::string
139 1 : Path::as_string () const
140 : {
141 : // FIXME: Impl for lang items
142 1 : rust_assert (kind == Kind::Regular);
143 :
144 1 : std::string str;
145 :
146 2 : for (const auto &segment : segments)
147 3 : str += segment.as_string () + "::";
148 :
149 : // basically a hack - remove last two characters of string (remove final ::)
150 1 : str.erase (str.length () - 2);
151 :
152 1 : return str;
153 : }
154 :
155 : SimplePath
156 2460 : Path::convert_to_simple_path (bool with_opening_scope_resolution) const
157 : {
158 2460 : rust_assert (kind == Kind::Regular);
159 :
160 2460 : if (!has_segments ())
161 0 : return SimplePath::create_empty ();
162 :
163 : // create vector of reserved size (to minimise reallocations)
164 2460 : std::vector<SimplePathSegment> simple_segments;
165 2460 : simple_segments.reserve (segments.size ());
166 :
167 4943 : for (const auto &segment : segments)
168 : {
169 : // return empty path if doesn't meet simple path segment requirements
170 2483 : if (segment.is_error () || segment.has_generic_args ())
171 0 : return SimplePath::create_empty ();
172 :
173 : // create segment and add to vector
174 2483 : std::string segment_str = segment.as_string ();
175 2483 : simple_segments.emplace_back (std::move (segment_str),
176 2483 : segment.get_locus ());
177 2483 : }
178 :
179 : // kind of a HACK to get locus depending on opening scope resolution
180 2460 : location_t locus = UNKNOWN_LOCATION;
181 2460 : if (with_opening_scope_resolution)
182 0 : locus = simple_segments[0].get_locus () - 2; // minus 2 chars for ::
183 : else
184 2460 : locus = simple_segments[0].get_locus ();
185 : // FIXME: this hack probably doesn't actually work
186 :
187 2460 : return SimplePath (std::move (simple_segments), with_opening_scope_resolution,
188 2460 : locus);
189 2460 : }
190 :
191 : void
192 472989 : PathInExpression::accept_vis (ASTVisitor &vis)
193 : {
194 472989 : vis.visit (*this);
195 472989 : }
196 :
197 : std::string
198 1 : PathInExpression::as_string () const
199 : {
200 1 : std::string str;
201 :
202 1 : if (has_opening_scope_resolution)
203 0 : str = "::";
204 :
205 1 : return str + Path::as_string ();
206 1 : }
207 :
208 : std::string
209 0 : TypePathSegmentGeneric::as_string () const
210 : {
211 : // TODO: rewrite to work with non-linearisable types
212 0 : return TypePathSegment::as_string () + "<" + generic_args.as_string () + ">";
213 : }
214 :
215 : std::string
216 0 : TypePathSegmentFunction::as_string () const
217 : {
218 : // TODO: rewrite to work with non-linearisable types
219 0 : return TypePathSegment::as_string () + function_path.as_string ();
220 : }
221 :
222 : std::string
223 258 : TypePath::as_string () const
224 : {
225 : /* TODO: this may need to be rewritten if a segment (e.g. function) can't be
226 : * literalised */
227 258 : std::string str;
228 :
229 258 : if (has_opening_scope_resolution)
230 0 : str = "::";
231 :
232 516 : for (const auto &segment : segments)
233 774 : str += segment->as_string () + "::";
234 :
235 : // kinda hack - remove last 2 '::' characters
236 258 : str.erase (str.length () - 2);
237 :
238 258 : return str;
239 : }
240 :
241 : SimplePath
242 30 : TypePath::as_simple_path () const
243 : {
244 30 : if (segments.empty ())
245 0 : return SimplePath::create_empty ();
246 :
247 : // create vector of reserved size (to minimise reallocations)
248 30 : std::vector<SimplePathSegment> simple_segments;
249 30 : simple_segments.reserve (segments.size ());
250 :
251 60 : for (const auto &segment : segments)
252 : {
253 : // return empty path if doesn't meet simple path segment requirements
254 30 : if (segment == nullptr || segment->is_error ()
255 60 : || !segment->is_ident_only () || segment->as_string () == "Self")
256 0 : return SimplePath::create_empty ();
257 :
258 : // create segment and add to vector
259 30 : std::string segment_str = segment->as_string ();
260 30 : simple_segments.emplace_back (std::move (segment_str),
261 30 : segment->get_locus ());
262 30 : }
263 :
264 30 : return SimplePath (std::move (simple_segments), has_opening_scope_resolution,
265 30 : locus);
266 30 : }
267 :
268 : std::string
269 25 : TypePath::make_debug_string () const
270 : {
271 25 : rust_assert (!segments.empty ());
272 :
273 25 : std::string output;
274 :
275 50 : for (const auto &segment : segments)
276 : {
277 25 : if (segment != nullptr && !segment->is_lang_item ()
278 50 : && !segment->is_error ())
279 : {
280 25 : if (!output.empty () || has_opening_scope_resolution_op ())
281 0 : output.append ("::");
282 75 : output.append (segment->get_ident_segment ().as_string ());
283 : }
284 : }
285 :
286 25 : return output;
287 : }
288 :
289 : // hopefully definition here will prevent circular dependency issue
290 : TraitBound *
291 3 : TypePath::to_trait_bound (bool in_parens) const
292 : {
293 : // If already in parentheses, don't convert to trait bound
294 : // This ensures (TypePath) stays as ParenthesisedType in the parser
295 3 : if (in_parens)
296 : return nullptr;
297 :
298 0 : return new TraitBound (TypePath (*this), get_locus (), in_parens);
299 : }
300 :
301 : std::string
302 0 : TypePathFunction::as_string () const
303 : {
304 : // TODO: rewrite to work with non-linearisable types
305 0 : std::string str ("(");
306 :
307 0 : if (has_inputs ())
308 : {
309 : auto i = inputs.begin ();
310 : auto e = inputs.end ();
311 :
312 0 : for (; i != e; i++)
313 : {
314 0 : str += (*i)->as_string ();
315 0 : if (e != i + 1)
316 0 : str += ", ";
317 : }
318 : }
319 :
320 0 : str += ")";
321 :
322 0 : if (has_return_type ())
323 0 : str += " -> " + return_type->as_string ();
324 :
325 0 : return str;
326 : }
327 :
328 : std::string
329 0 : QualifiedPathInExpression::as_string () const
330 : {
331 0 : return path_type.as_string () + "::" + Path::as_string ();
332 : }
333 :
334 : std::string
335 0 : QualifiedPathInType::as_string () const
336 : {
337 : /* TODO: this may need adjusting if segments (e.g. with functions) can't be
338 : * literalised */
339 0 : std::string str = path_type.as_string ();
340 :
341 0 : str += "::" + associated_segment->as_string ();
342 0 : for (const auto &segment : segments)
343 0 : str += "::" + segment->as_string ();
344 :
345 0 : return str;
346 : }
347 :
348 : void
349 1555 : ConstGenericParam::accept_vis (ASTVisitor &vis)
350 : {
351 1555 : vis.visit (*this);
352 1555 : }
353 :
354 : void
355 1057431 : TypePathSegment::accept_vis (ASTVisitor &vis)
356 : {
357 1057431 : vis.visit (*this);
358 1057431 : }
359 :
360 : void
361 55954 : TypePathSegmentGeneric::accept_vis (ASTVisitor &vis)
362 : {
363 55954 : vis.visit (*this);
364 55954 : }
365 :
366 : void
367 474 : TypePathSegmentFunction::accept_vis (ASTVisitor &vis)
368 : {
369 474 : vis.visit (*this);
370 474 : }
371 :
372 : void
373 989153 : TypePath::accept_vis (ASTVisitor &vis)
374 : {
375 989153 : vis.visit (*this);
376 989153 : }
377 :
378 : void
379 2235 : QualifiedPathInExpression::accept_vis (ASTVisitor &vis)
380 : {
381 2235 : vis.visit (*this);
382 2235 : }
383 :
384 : void
385 5905 : QualifiedPathInType::accept_vis (ASTVisitor &vis)
386 : {
387 5905 : vis.visit (*this);
388 5905 : }
389 :
390 : } // namespace AST
391 : } // namespace Rust
|