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 : 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 : 2309 : GenericArg::disambiguate_to_type () const
96 : : {
97 : 2309 : rust_assert (get_kind () == Kind::Either);
98 : :
99 : 2309 : auto segment = std::unique_ptr<TypePathSegment> (
100 : 4618 : new TypePathSegment (path.as_string (), false, locus));
101 : 2309 : auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
102 : 2309 : segments.emplace_back (std::move (segment));
103 : :
104 : 2309 : return GenericArg::create_type (
105 : 2309 : std::unique_ptr<Type> (new TypePath (std::move (segments), locus)));
106 : 2309 : }
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 : 52797 : PathExprSegment::as_string () const
129 : : {
130 : : // TODO: rewrite dump to work with non-literalisable types
131 : 52797 : std::string ident_str = segment_name.as_string ();
132 : 52797 : if (has_generic_args ())
133 : 0 : ident_str += "::<" + generic_args.as_string () + ">";
134 : :
135 : 52797 : 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 : 52545 : Path::convert_to_simple_path (bool with_opening_scope_resolution) const
157 : : {
158 : 52545 : rust_assert (kind == Kind::Regular);
159 : :
160 : 52545 : if (!has_segments ())
161 : 0 : return SimplePath::create_empty ();
162 : :
163 : : // create vector of reserved size (to minimise reallocations)
164 : 52545 : std::vector<SimplePathSegment> simple_segments;
165 : 52545 : simple_segments.reserve (segments.size ());
166 : :
167 : 105341 : for (const auto &segment : segments)
168 : : {
169 : : // return empty path if doesn't meet simple path segment requirements
170 : 52796 : if (segment.is_error () || segment.has_generic_args ())
171 : 0 : return SimplePath::create_empty ();
172 : :
173 : : // create segment and add to vector
174 : 52796 : std::string segment_str = segment.as_string ();
175 : 52796 : simple_segments.emplace_back (std::move (segment_str),
176 : 52796 : segment.get_locus ());
177 : 52796 : }
178 : :
179 : : // kind of a HACK to get locus depending on opening scope resolution
180 : 52545 : location_t locus = UNKNOWN_LOCATION;
181 : 52545 : if (with_opening_scope_resolution)
182 : 0 : locus = simple_segments[0].get_locus () - 2; // minus 2 chars for ::
183 : : else
184 : 52545 : locus = simple_segments[0].get_locus ();
185 : : // FIXME: this hack probably doesn't actually work
186 : :
187 : 52545 : return SimplePath (std::move (simple_segments), with_opening_scope_resolution,
188 : 52545 : locus);
189 : 52545 : }
190 : :
191 : : void
192 : 13518040 : PathInExpression::accept_vis (ASTVisitor &vis)
193 : : {
194 : 13518040 : vis.visit (*this);
195 : 13518040 : }
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 : 0 : 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 : 0 : std::string str;
228 : :
229 : 0 : if (has_opening_scope_resolution)
230 : 0 : str = "::";
231 : :
232 : 0 : for (const auto &segment : segments)
233 : 0 : str += segment->as_string () + "::";
234 : :
235 : : // kinda hack - remove last 2 '::' characters
236 : 0 : str.erase (str.length () - 2);
237 : :
238 : 0 : return str;
239 : : }
240 : :
241 : : SimplePath
242 : 497 : TypePath::as_simple_path () const
243 : : {
244 : 497 : if (segments.empty ())
245 : 0 : return SimplePath::create_empty ();
246 : :
247 : : // create vector of reserved size (to minimise reallocations)
248 : 497 : std::vector<SimplePathSegment> simple_segments;
249 : 497 : simple_segments.reserve (segments.size ());
250 : :
251 : 994 : for (const auto &segment : segments)
252 : : {
253 : : // return empty path if doesn't meet simple path segment requirements
254 : 497 : if (segment == nullptr || segment->is_error ()
255 : 994 : || !segment->is_ident_only () || segment->as_string () == "Self")
256 : 0 : return SimplePath::create_empty ();
257 : :
258 : : // create segment and add to vector
259 : 497 : std::string segment_str = segment->as_string ();
260 : 497 : simple_segments.emplace_back (std::move (segment_str),
261 : 497 : segment->get_locus ());
262 : 497 : }
263 : :
264 : 497 : return SimplePath (std::move (simple_segments), has_opening_scope_resolution,
265 : 497 : locus);
266 : 497 : }
267 : :
268 : : std::string
269 : 23 : TypePath::make_debug_string () const
270 : : {
271 : 23 : rust_assert (!segments.empty ());
272 : :
273 : 23 : std::string output;
274 : :
275 : 46 : for (const auto &segment : segments)
276 : : {
277 : 23 : if (segment != nullptr && !segment->is_lang_item ()
278 : 46 : && !segment->is_error ())
279 : : {
280 : 23 : if (!output.empty () || has_opening_scope_resolution_op ())
281 : 0 : output.append ("::");
282 : 69 : output.append (segment->get_ident_segment ().as_string ());
283 : : }
284 : : }
285 : :
286 : 23 : 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 : 3 : return new TraitBound (TypePath (*this), get_locus (), in_parens);
294 : : }
295 : :
296 : : std::string
297 : 0 : TypePathFunction::as_string () const
298 : : {
299 : : // TODO: rewrite to work with non-linearisable types
300 : 0 : std::string str ("(");
301 : :
302 : 0 : if (has_inputs ())
303 : : {
304 : : auto i = inputs.begin ();
305 : : auto e = inputs.end ();
306 : :
307 : 0 : for (; i != e; i++)
308 : : {
309 : 0 : str += (*i)->as_string ();
310 : 0 : if (e != i + 1)
311 : 0 : str += ", ";
312 : : }
313 : : }
314 : :
315 : 0 : str += ")";
316 : :
317 : 0 : if (has_return_type ())
318 : 0 : str += " -> " + return_type->as_string ();
319 : :
320 : 0 : return str;
321 : : }
322 : :
323 : : std::string
324 : 0 : QualifiedPathInExpression::as_string () const
325 : : {
326 : 0 : return path_type.as_string () + "::" + Path::as_string ();
327 : : }
328 : :
329 : : std::string
330 : 0 : QualifiedPathInType::as_string () const
331 : : {
332 : : /* TODO: this may need adjusting if segments (e.g. with functions) can't be
333 : : * literalised */
334 : 0 : std::string str = path_type.as_string ();
335 : :
336 : 0 : str += "::" + associated_segment->as_string ();
337 : 0 : for (const auto &segment : segments)
338 : 0 : str += "::" + segment->as_string ();
339 : :
340 : 0 : return str;
341 : : }
342 : :
343 : : void
344 : 12744 : ConstGenericParam::accept_vis (ASTVisitor &vis)
345 : : {
346 : 12744 : vis.visit (*this);
347 : 12744 : }
348 : :
349 : : void
350 : 12069555 : TypePathSegment::accept_vis (ASTVisitor &vis)
351 : : {
352 : 12069555 : vis.visit (*this);
353 : 12069555 : }
354 : :
355 : : void
356 : 2775586 : TypePathSegmentGeneric::accept_vis (ASTVisitor &vis)
357 : : {
358 : 2775586 : vis.visit (*this);
359 : 2775586 : }
360 : :
361 : : void
362 : 96509 : TypePathSegmentFunction::accept_vis (ASTVisitor &vis)
363 : : {
364 : 96509 : vis.visit (*this);
365 : 96509 : }
366 : :
367 : : void
368 : 10989945 : TypePath::accept_vis (ASTVisitor &vis)
369 : : {
370 : 10989945 : vis.visit (*this);
371 : 10989945 : }
372 : :
373 : : void
374 : 24114 : QualifiedPathInExpression::accept_vis (ASTVisitor &vis)
375 : : {
376 : 24114 : vis.visit (*this);
377 : 24114 : }
378 : :
379 : : void
380 : 528771 : QualifiedPathInType::accept_vis (ASTVisitor &vis)
381 : : {
382 : 528771 : vis.visit (*this);
383 : 528771 : }
384 : :
385 : : } // namespace AST
386 : : } // namespace Rust
|