Branch data Line data Source code
1 : : /* General AST-related method implementations for Rust frontend.
2 : : Copyright (C) 2009-2025 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 : 10 : GenericArg::disambiguate_to_const () const
86 : : {
87 : 10 : rust_assert (get_kind () == Kind::Either);
88 : :
89 : : // FIXME: is it fine to have no outer attributes?
90 : 10 : return GenericArg::create_const (
91 : 10 : std::unique_ptr<Expr> (new IdentifierExpr (path, {}, locus)));
92 : : }
93 : :
94 : : GenericArg
95 : 2285 : GenericArg::disambiguate_to_type () const
96 : : {
97 : 2285 : rust_assert (get_kind () == Kind::Either);
98 : :
99 : 2285 : auto segment = std::unique_ptr<TypePathSegment> (
100 : 4570 : new TypePathSegment (path.as_string (), false, locus));
101 : 2285 : auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
102 : 2285 : segments.emplace_back (std::move (segment));
103 : :
104 : 2285 : return GenericArg::create_type (
105 : 2285 : std::unique_ptr<Type> (new TypePath (std::move (segments), locus)));
106 : 2285 : }
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 : 4871 : PathExprSegment::as_string () const
129 : : {
130 : : // TODO: rewrite dump to work with non-literalisable types
131 : 4871 : std::string ident_str = segment_name.as_string ();
132 : 4871 : if (has_generic_args ())
133 : 0 : ident_str += "::<" + generic_args.as_string () + ">";
134 : :
135 : 4871 : 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 : 2412 : Path::convert_to_simple_path (bool with_opening_scope_resolution) const
157 : : {
158 : 2412 : rust_assert (kind == Kind::Regular);
159 : :
160 : 2412 : if (!has_segments ())
161 : 0 : return SimplePath::create_empty ();
162 : :
163 : : // create vector of reserved size (to minimise reallocations)
164 : 2412 : std::vector<SimplePathSegment> simple_segments;
165 : 2412 : simple_segments.reserve (segments.size ());
166 : :
167 : 4847 : for (const auto &segment : segments)
168 : : {
169 : : // return empty path if doesn't meet simple path segment requirements
170 : 7305 : if (segment.is_error () || segment.has_generic_args ()
171 : 4870 : || segment.as_string () == "Self")
172 : 0 : return SimplePath::create_empty ();
173 : :
174 : : // create segment and add to vector
175 : 2435 : std::string segment_str = segment.as_string ();
176 : 4870 : simple_segments.push_back (
177 : 4870 : SimplePathSegment (std::move (segment_str), segment.get_locus ()));
178 : 2435 : }
179 : :
180 : : // kind of a HACK to get locus depending on opening scope resolution
181 : 2412 : location_t locus = UNKNOWN_LOCATION;
182 : 2412 : if (with_opening_scope_resolution)
183 : 0 : locus = simple_segments[0].get_locus () - 2; // minus 2 chars for ::
184 : : else
185 : 2412 : locus = simple_segments[0].get_locus ();
186 : : // FIXME: this hack probably doesn't actually work
187 : :
188 : 2412 : return SimplePath (std::move (simple_segments), with_opening_scope_resolution,
189 : 2412 : locus);
190 : 2412 : }
191 : :
192 : : void
193 : 461673 : PathInExpression::accept_vis (ASTVisitor &vis)
194 : : {
195 : 461673 : vis.visit (*this);
196 : 461673 : }
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 : 0 : 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 : 0 : std::string str;
229 : :
230 : 0 : if (has_opening_scope_resolution)
231 : 0 : str = "::";
232 : :
233 : 0 : for (const auto &segment : segments)
234 : 0 : str += segment->as_string () + "::";
235 : :
236 : : // kinda hack - remove last 2 '::' characters
237 : 0 : str.erase (str.length () - 2);
238 : :
239 : 0 : return str;
240 : : }
241 : :
242 : : SimplePath
243 : 29 : TypePath::as_simple_path () const
244 : : {
245 : 29 : if (segments.empty ())
246 : 0 : return SimplePath::create_empty ();
247 : :
248 : : // create vector of reserved size (to minimise reallocations)
249 : 29 : std::vector<SimplePathSegment> simple_segments;
250 : 29 : simple_segments.reserve (segments.size ());
251 : :
252 : 58 : for (const auto &segment : segments)
253 : : {
254 : : // return empty path if doesn't meet simple path segment requirements
255 : 29 : if (segment == nullptr || segment->is_error ()
256 : 58 : || !segment->is_ident_only () || segment->as_string () == "Self")
257 : 0 : return SimplePath::create_empty ();
258 : :
259 : : // create segment and add to vector
260 : 29 : std::string segment_str = segment->as_string ();
261 : 58 : simple_segments.push_back (
262 : 58 : SimplePathSegment (std::move (segment_str), segment->get_locus ()));
263 : 29 : }
264 : :
265 : 29 : return SimplePath (std::move (simple_segments), has_opening_scope_resolution,
266 : 29 : locus);
267 : 29 : }
268 : :
269 : : std::string
270 : 21 : TypePath::make_debug_string () const
271 : : {
272 : 21 : rust_assert (!segments.empty ());
273 : :
274 : 21 : std::string output;
275 : :
276 : 42 : for (const auto &segment : segments)
277 : : {
278 : 21 : if (segment != nullptr && !segment->is_lang_item ()
279 : 42 : && !segment->is_error ())
280 : : {
281 : 21 : if (!output.empty () || has_opening_scope_resolution_op ())
282 : 0 : output.append ("::");
283 : 63 : output.append (segment->get_ident_segment ().as_string ());
284 : : }
285 : : }
286 : :
287 : 21 : return output;
288 : : }
289 : :
290 : : // hopefully definition here will prevent circular dependency issue
291 : : TraitBound *
292 : 0 : TypePath::to_trait_bound (bool in_parens) const
293 : : {
294 : 0 : return new TraitBound (TypePath (*this), get_locus (), in_parens);
295 : : }
296 : :
297 : : std::string
298 : 0 : TypePathFunction::as_string () const
299 : : {
300 : : // TODO: rewrite to work with non-linearisable types
301 : 0 : std::string str ("(");
302 : :
303 : 0 : if (has_inputs ())
304 : : {
305 : : auto i = inputs.begin ();
306 : : auto e = inputs.end ();
307 : :
308 : 0 : for (; i != e; i++)
309 : : {
310 : 0 : str += (*i)->as_string ();
311 : 0 : if (e != i + 1)
312 : 0 : str += ", ";
313 : : }
314 : : }
315 : :
316 : 0 : str += ")";
317 : :
318 : 0 : if (has_return_type ())
319 : 0 : str += " -> " + return_type->as_string ();
320 : :
321 : 0 : return str;
322 : : }
323 : :
324 : : std::string
325 : 0 : QualifiedPathInExpression::as_string () const
326 : : {
327 : 0 : return path_type.as_string () + "::" + Path::as_string ();
328 : : }
329 : :
330 : : std::string
331 : 0 : QualifiedPathInType::as_string () const
332 : : {
333 : : /* TODO: this may need adjusting if segments (e.g. with functions) can't be
334 : : * literalised */
335 : 0 : std::string str = path_type.as_string ();
336 : :
337 : 0 : str += "::" + associated_segment->as_string ();
338 : 0 : for (const auto &segment : segments)
339 : 0 : str += "::" + segment->as_string ();
340 : :
341 : 0 : return str;
342 : : }
343 : :
344 : : void
345 : 725 : ConstGenericParam::accept_vis (ASTVisitor &vis)
346 : : {
347 : 725 : vis.visit (*this);
348 : 725 : }
349 : :
350 : : void
351 : 1026341 : TypePathSegment::accept_vis (ASTVisitor &vis)
352 : : {
353 : 1026341 : vis.visit (*this);
354 : 1026341 : }
355 : :
356 : : void
357 : 54380 : TypePathSegmentGeneric::accept_vis (ASTVisitor &vis)
358 : : {
359 : 54380 : vis.visit (*this);
360 : 54380 : }
361 : :
362 : : void
363 : 474 : TypePathSegmentFunction::accept_vis (ASTVisitor &vis)
364 : : {
365 : 474 : vis.visit (*this);
366 : 474 : }
367 : :
368 : : void
369 : 961138 : TypePath::accept_vis (ASTVisitor &vis)
370 : : {
371 : 961138 : vis.visit (*this);
372 : 961138 : }
373 : :
374 : : void
375 : 2194 : QualifiedPathInExpression::accept_vis (ASTVisitor &vis)
376 : : {
377 : 2194 : vis.visit (*this);
378 : 2194 : }
379 : :
380 : : void
381 : 5608 : QualifiedPathInType::accept_vis (ASTVisitor &vis)
382 : : {
383 : 5608 : vis.visit (*this);
384 : 5608 : }
385 : :
386 : : } // namespace AST
387 : : } // namespace Rust
|