Branch data Line data Source code
1 : : // Copyright (C) 2025 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 "rust-desugar-apit.h"
20 : : #include "rust-ast.h"
21 : : #include "rust-type.h"
22 : :
23 : : namespace Rust {
24 : : namespace AST {
25 : :
26 : 71518 : class DesugarApitType : public DefaultASTVisitor
27 : : {
28 : : using DefaultASTVisitor::visit;
29 : :
30 : : public:
31 : : static std::pair<AST::Type *, std::vector<std::unique_ptr<GenericParam>>>
32 : 35759 : Desugar (AST::Type &type)
33 : : {
34 : 35759 : DesugarApitType visitor (&type);
35 : 35759 : type.accept_vis (visitor);
36 : 35759 : rust_assert (visitor.translated != nullptr);
37 : 35759 : return std::make_pair (visitor.translated,
38 : 35759 : std::move (visitor.implicit_generic_params));
39 : 35759 : }
40 : :
41 : : // Generate a unique impl trait parameter name
42 : 122 : static Identifier get_impl_name ()
43 : : {
44 : 122 : static size_t counter = 0;
45 : 244 : return Identifier ("Impl_" + std::to_string (counter++));
46 : : }
47 : :
48 : : // these can hold other types
49 : 185 : void visit (AST::TupleType &tuple) override
50 : : {
51 : 928 : for (auto &elem : tuple.get_elems ())
52 : : {
53 : 743 : auto &type = *elem.get ();
54 : 743 : auto desugar = Desugar (type);
55 : 743 : auto tt = desugar.first;
56 : :
57 : 743 : auto &implicit_generics = desugar.second;
58 : 743 : if (implicit_generics.empty ())
59 : 729 : continue;
60 : :
61 : 14 : if (tt != elem.get ())
62 : 14 : elem = std::unique_ptr<Type> (tt);
63 : :
64 : 28 : for (auto &implicit_generic : implicit_generics)
65 : 14 : implicit_generic_params.push_back (std::move (implicit_generic));
66 : 743 : }
67 : 185 : }
68 : :
69 : 445 : void visit (AST::ArrayType &type) override
70 : : {
71 : 445 : auto &element_type = type.get_element_type ();
72 : 445 : auto desugar = Desugar (*element_type);
73 : 445 : auto tt = desugar.first;
74 : :
75 : 445 : auto &implicit_generics = desugar.second;
76 : 445 : if (implicit_generics.empty ())
77 : 445 : return;
78 : :
79 : 0 : if (tt != element_type.get ())
80 : 0 : element_type = std::unique_ptr<AST::Type> (tt);
81 : :
82 : 0 : for (auto &implicit_generic : implicit_generics)
83 : 0 : implicit_generic_params.push_back (std::move (implicit_generic));
84 : 445 : }
85 : :
86 : 6713 : void visit (AST::ReferenceType &type) override
87 : : {
88 : : // Get a reference to the current type for in-place modification
89 : 6713 : auto &referenced_type = type.get_type_referenced ();
90 : 6713 : auto desugar = Desugar (referenced_type);
91 : 6713 : auto tt = desugar.first;
92 : :
93 : 6713 : auto &implicit_generics = desugar.second;
94 : 6713 : if (implicit_generics.empty ())
95 : 6695 : return;
96 : :
97 : : // Update the reference type's contents rather than creating a new one
98 : 18 : if (&referenced_type != tt)
99 : : {
100 : 18 : std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
101 : 18 : static_cast<AST::TypeNoBounds *> (tt));
102 : 18 : type.get_type_ptr () = std::move (new_type_no_bounds);
103 : 18 : }
104 : :
105 : : // Collect all the implicit generic parameters we found
106 : 36 : for (auto &implicit_generic : implicit_generics)
107 : 18 : implicit_generic_params.push_back (std::move (implicit_generic));
108 : 6713 : }
109 : :
110 : 2191 : void visit (AST::RawPointerType &type) override
111 : : {
112 : 2191 : auto &pointed_type = type.get_type_pointed_to ();
113 : 2191 : auto desugar = Desugar (pointed_type);
114 : 2191 : auto tt = desugar.first;
115 : :
116 : 2191 : auto &implicit_generics = desugar.second;
117 : 2191 : if (implicit_generics.empty ())
118 : 2191 : return;
119 : :
120 : : // Update the pointer's inner type directly using the new accessor
121 : 0 : if (&pointed_type != tt)
122 : : {
123 : 0 : std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
124 : 0 : static_cast<AST::TypeNoBounds *> (tt));
125 : 0 : type.get_type_ptr () = std::move (new_type_no_bounds);
126 : 0 : }
127 : :
128 : : // Collect all the implicit generic parameters we found
129 : 0 : for (auto &implicit_generic : implicit_generics)
130 : 0 : implicit_generic_params.push_back (std::move (implicit_generic));
131 : 2191 : }
132 : :
133 : 445 : void visit (AST::SliceType &type) override
134 : : {
135 : 445 : auto &element_type = type.get_elem_type ();
136 : 445 : auto desugar = Desugar (element_type);
137 : 445 : auto tt = desugar.first;
138 : :
139 : 445 : auto &implicit_generics = desugar.second;
140 : 445 : if (implicit_generics.empty ())
141 : 445 : return;
142 : :
143 : 0 : if (&element_type != tt)
144 : : {
145 : 0 : std::unique_ptr<AST::Type> new_elem_type (tt);
146 : 0 : type.get_elem_type_ptr () = std::move (new_elem_type);
147 : 0 : }
148 : :
149 : : // Collect all the implicit generic parameters we found
150 : 0 : for (auto &implicit_generic : implicit_generics)
151 : 0 : implicit_generic_params.push_back (std::move (implicit_generic));
152 : 445 : }
153 : :
154 : 3 : void visit (AST::ParenthesisedType &type) override
155 : : {
156 : 3 : auto &inner_type_ptr = type.get_type_in_parens ();
157 : 3 : auto desugar = Desugar (*inner_type_ptr);
158 : 3 : auto tt = desugar.first;
159 : :
160 : 3 : auto &implicit_generics = desugar.second;
161 : 3 : if (implicit_generics.empty ())
162 : 3 : return;
163 : :
164 : 0 : if (inner_type_ptr.get () != tt)
165 : : {
166 : 0 : std::unique_ptr<AST::Type> new_inner_type (tt);
167 : 0 : inner_type_ptr = std::move (new_inner_type);
168 : 0 : }
169 : :
170 : : // Collect all the implicit generic parameters we found
171 : 0 : for (auto &implicit_generic : implicit_generics)
172 : 0 : implicit_generic_params.push_back (std::move (implicit_generic));
173 : 3 : }
174 : :
175 : : // this is where the desugar happens
176 : 0 : void visit (AST::ImplTraitType &type) override
177 : : {
178 : : // Generate a unique name using the static method
179 : 0 : auto ident = get_impl_name ();
180 : :
181 : : // Create a type path for the new generic parameter
182 : : // Create a SimplePathSegment with the identifier string
183 : 0 : auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ());
184 : : // Create a vector of SimplePathSegments for SimplePath constructor
185 : 0 : std::vector<SimplePathSegment> simple_segs = {simple_seg};
186 : : // Create a SimplePath
187 : 0 : auto simple_path = SimplePath (simple_segs, false, type.get_locus ());
188 : :
189 : : // Convert to TypePath by creating path segments
190 : 0 : std::vector<std::unique_ptr<TypePathSegment>> segments;
191 : 0 : segments.emplace_back (
192 : 0 : new TypePathSegment (PathIdentSegment (ident.as_string (),
193 : 0 : type.get_locus ()),
194 : 0 : false, type.get_locus ()));
195 : :
196 : : // Create TypePath from segments
197 : 0 : auto type_path
198 : 0 : = new TypePath (std::move (segments), type.get_locus (), false);
199 : :
200 : : // Convert bounds from impl trait to generic parameter bounds
201 : 0 : std::vector<std::unique_ptr<TypeParamBound>> bounds;
202 : 0 : bounds.reserve (type.get_type_param_bounds ().size ());
203 : :
204 : 0 : for (auto &bound : type.get_type_param_bounds ())
205 : 0 : bounds.push_back (bound->clone_type_param_bound ());
206 : :
207 : : // Create the new generic parameter
208 : 0 : auto generic_param = std::unique_ptr<TypeParam> (
209 : : new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
210 : 0 : true /*from impl trait*/));
211 : :
212 : : // Store the generic parameter to be added to the function signature
213 : 0 : implicit_generic_params.push_back (std::move (generic_param));
214 : :
215 : : // Replace impl trait with the new type parameter
216 : 0 : translated = type_path;
217 : 0 : }
218 : :
219 : 122 : void visit (AST::ImplTraitTypeOneBound &type) override
220 : : {
221 : : // Generate a unique name using the static method
222 : 122 : auto ident = get_impl_name ();
223 : :
224 : : // Create a type path for the new generic parameter
225 : : // Create a SimplePathSegment with the identifier string
226 : 244 : auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ());
227 : : // Create a vector of SimplePathSegments for SimplePath constructor
228 : 244 : std::vector<SimplePathSegment> simple_segs = {simple_seg};
229 : : // Create a SimplePath
230 : 122 : auto simple_path = SimplePath (simple_segs, false, type.get_locus ());
231 : :
232 : : // Convert to TypePath by creating path segments
233 : 122 : std::vector<std::unique_ptr<TypePathSegment>> segments;
234 : 122 : segments.emplace_back (
235 : 244 : new TypePathSegment (PathIdentSegment (ident.as_string (),
236 : 244 : type.get_locus ()),
237 : 244 : false, type.get_locus ()));
238 : :
239 : : // Create TypePath from segments
240 : 122 : auto type_path
241 : 122 : = new TypePath (std::move (segments), type.get_locus (), false);
242 : :
243 : : // Convert the bound to a generic parameter bound
244 : 122 : std::vector<std::unique_ptr<TypeParamBound>> bounds;
245 : 122 : bounds.push_back (std::move (type.get_trait_bound ()));
246 : :
247 : : // Create the new generic parameter
248 : 122 : auto generic_param = std::unique_ptr<TypeParam> (
249 : : new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
250 : 122 : true /*from impl trait*/));
251 : :
252 : : // Store the generic parameter to be added to the function signature
253 : 122 : implicit_generic_params.push_back (std::move (generic_param));
254 : :
255 : : // Replace impl trait with the new type parameter
256 : 122 : translated = type_path;
257 : 122 : }
258 : :
259 : : private:
260 : 35759 : DesugarApitType (AST::Type *base)
261 : 35759 : : translated (base), implicit_generic_params ()
262 : : {}
263 : :
264 : : AST::Type *translated;
265 : : std::vector<std::unique_ptr<GenericParam>> implicit_generic_params;
266 : : };
267 : :
268 : : // ---------
269 : :
270 : 208 : class ApitBoundProcessor
271 : : {
272 : : public:
273 : 104 : ApitBoundProcessor (
274 : : WhereClause &where_clause,
275 : : std::vector<std::unique_ptr<GenericParam>> &generic_params)
276 : 104 : : where_clause (where_clause), generic_params (generic_params)
277 : : {}
278 : :
279 : 104 : void go (std::vector<std::unique_ptr<GenericParam>> &implicit_generics)
280 : : {
281 : : // some desugars are more complex so imagine this case
282 : : //
283 : : // pub fn foo(_value: impl Bar<Baz = impl Foo>) -> i32 {
284 : : // 15
285 : : // }
286 : : //
287 : : // this needs to become:
288 : : //
289 : : // pub fn foo<T, U>(_value: T) -> i32
290 : : // where
291 : : // T: Bar<Baz = U>,
292 : : // U: Foo,
293 : : // {
294 : : // 15
295 : : // }
296 : : //
297 : : // so we need to walk all the implicit generics and the trait bounds paths
298 : : // for more generics
299 : :
300 : 215 : for (auto &implicit_generic : implicit_generics)
301 : : {
302 : 111 : switch (implicit_generic->get_kind ())
303 : : {
304 : 111 : case GenericParam::Kind::Type:
305 : 111 : {
306 : 111 : TypeParam &p
307 : 111 : = *static_cast<TypeParam *> (implicit_generic.get ());
308 : :
309 : 111 : process_type_param (p);
310 : 111 : generic_params.push_back (std::move (implicit_generic));
311 : 122 : for (auto &synth : synthetic_params)
312 : 11 : generic_params.push_back (std::move (synth));
313 : 111 : synthetic_params.clear ();
314 : : }
315 : 111 : break;
316 : :
317 : 0 : default:
318 : 0 : generic_params.push_back (std::move (implicit_generic));
319 : 0 : break;
320 : : }
321 : : }
322 : 104 : }
323 : :
324 : : private:
325 : 111 : void process_type_param (TypeParam &p)
326 : : {
327 : 111 : auto &bounds = p.get_type_param_bounds ();
328 : 111 : std::vector<size_t> bounds_to_remove;
329 : 222 : for (size_t i = 0; i < bounds.size (); i++)
330 : : {
331 : 111 : auto &tb = bounds[i];
332 : 111 : switch (tb->get_bound_type ())
333 : : {
334 : 111 : case TypeParamBound::TypeParamBoundType::TRAIT:
335 : 111 : {
336 : 111 : TraitBound &ttb = *static_cast<TraitBound *> (tb.get ());
337 : 111 : TypePath &path = ttb.get_type_path ();
338 : 111 : bool deusgared = process_type_path (p, ttb, path);
339 : 111 : if (deusgared)
340 : 11 : bounds_to_remove.push_back (i);
341 : : }
342 : :
343 : 111 : default:
344 : 111 : break;
345 : : }
346 : : }
347 : 122 : for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend ();
348 : 11 : ++it)
349 : 11 : bounds.erase (bounds.begin () + *it);
350 : 111 : }
351 : :
352 : 111 : bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path)
353 : : {
354 : 111 : bool desugared = false;
355 : 222 : for (auto &segment : path.get_segments ())
356 : : {
357 : 111 : switch (segment->get_type ())
358 : : {
359 : 11 : case TypePathSegment::SegmentType::GENERIC:
360 : 11 : {
361 : 11 : TypePathSegmentGeneric &seg
362 : 11 : = *static_cast<TypePathSegmentGeneric *> (segment.get ());
363 : 11 : desugared |= process_generic_segment (p, parent, path, seg);
364 : : }
365 : :
366 : 111 : default:
367 : 111 : break;
368 : : }
369 : : }
370 : 111 : return desugared;
371 : : }
372 : :
373 : 11 : bool process_generic_segment (TypeParam &p, TraitBound &parent,
374 : : TypePath &path, TypePathSegmentGeneric &seg)
375 : : {
376 : : // we need to look for any impl types as default arguments in any generics
377 : : // and remove this index from the generic arguments by using a where
378 : : // constraint instead
379 : :
380 : 11 : std::vector<std::unique_ptr<WhereClauseItem>> new_clauses;
381 : 11 : GenericArgs &generic_args = seg.get_generic_args ();
382 : 11 : std::vector<std::reference_wrapper<const GenericArgsBinding>>
383 : 11 : bindings_desugared;
384 : 11 : std::vector<GenericArgsBinding> &bindings
385 : 11 : = generic_args.get_binding_args ();
386 : :
387 : 22 : for (auto &generic : bindings)
388 : : {
389 : 11 : auto &t = generic.get_type ();
390 : 11 : auto translated = DesugarApitType::Desugar (t);
391 : 11 : auto tt = translated.first;
392 : :
393 : 11 : auto &implicit_generics = translated.second;
394 : 11 : if (implicit_generics.empty ())
395 : 0 : continue;
396 : :
397 : 11 : if (tt != &t)
398 : : {
399 : 11 : bindings_desugared.push_back (generic);
400 : 11 : generic.get_type_ptr () = std::unique_ptr<Type> (tt);
401 : : }
402 : :
403 : 22 : for (auto &implicit_generic : implicit_generics)
404 : : {
405 : 11 : switch (implicit_generic->get_kind ())
406 : : {
407 : 11 : case GenericParam::Kind::Type:
408 : 11 : {
409 : 11 : TypeParam &tp
410 : 11 : = *static_cast<TypeParam *> (implicit_generic.get ());
411 : :
412 : 11 : std::vector<std::unique_ptr<TypeParamBound>>
413 : 11 : type_param_bounds;
414 : 11 : type_param_bounds.reserve (
415 : 11 : tp.get_type_param_bounds ().size ());
416 : :
417 : 22 : for (auto &b : tp.get_type_param_bounds ())
418 : 11 : type_param_bounds.push_back (std::move (b));
419 : 11 : tp.get_type_param_bounds ().clear ();
420 : :
421 : : // add synthetic parameter for this
422 : 11 : synthetic_params.push_back (std::move (implicit_generic));
423 : :
424 : 11 : auto bound_type_path
425 : 11 : = get_type_for_identifier (tp.get_type_representation ());
426 : :
427 : 11 : auto clause = new TypeBoundWhereClauseItem (
428 : : {}, std::move (bound_type_path),
429 : 11 : std::move (type_param_bounds), tp.get_locus ());
430 : 11 : std::unique_ptr<WhereClauseItem> clause_item
431 : 11 : = std::unique_ptr<WhereClauseItem> (clause);
432 : 11 : new_clauses.push_back (std::move (clause_item));
433 : 11 : }
434 : 11 : break;
435 : :
436 : 0 : default:
437 : 0 : synthetic_params.push_back (std::move (implicit_generic));
438 : 0 : break;
439 : : }
440 : : }
441 : 11 : }
442 : :
443 : 22 : std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
444 : 22 : auto bound = std::unique_ptr<TypeParamBound> (new TraitBound (parent));
445 : 11 : type_param_bounds.push_back (std::move (bound));
446 : 11 : auto parent_type_path
447 : 22 : = get_type_for_identifier (p.get_type_representation ());
448 : 11 : auto clause
449 : : = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path),
450 : : std::move (type_param_bounds),
451 : 11 : parent.get_locus ());
452 : 11 : std::unique_ptr<WhereClauseItem> clause_item
453 : 11 : = std::unique_ptr<WhereClauseItem> (clause);
454 : 11 : where_clause.get_items ().push_back (std::move (clause_item));
455 : :
456 : 22 : for (auto &where_item : new_clauses)
457 : 11 : where_clause.get_items ().push_back (std::move (where_item));
458 : :
459 : 11 : return !bindings_desugared.empty ();
460 : 11 : }
461 : :
462 : 22 : static std::unique_ptr<Type> get_type_for_identifier (const Identifier &ident)
463 : : {
464 : 22 : auto simple_seg
465 : 44 : = SimplePathSegment (ident.as_string (), ident.get_locus ());
466 : 44 : std::vector<SimplePathSegment> simple_segs = {simple_seg};
467 : 22 : auto simple_path = SimplePath (simple_segs, false, ident.get_locus ());
468 : 22 : std::vector<std::unique_ptr<TypePathSegment>> segments;
469 : 22 : segments.emplace_back (
470 : 66 : new TypePathSegment (PathIdentSegment (ident.as_string (),
471 : 44 : ident.get_locus ()),
472 : 44 : false, ident.get_locus ()));
473 : 22 : auto type_path = new TypePath (std::move (segments), ident.get_locus ());
474 : 22 : return std::unique_ptr<Type> (type_path);
475 : 22 : }
476 : :
477 : : private:
478 : : WhereClause &where_clause;
479 : : std::vector<std::unique_ptr<GenericParam>> &generic_params;
480 : :
481 : : // mutates
482 : : std::vector<std::unique_ptr<GenericParam>> synthetic_params;
483 : : };
484 : :
485 : : // ---------
486 : :
487 : 4354 : DesugarApit::DesugarApit () {}
488 : :
489 : : void
490 : 4354 : DesugarApit::go (AST::Crate &crate)
491 : : {
492 : 4354 : DefaultASTVisitor::visit (crate);
493 : 4354 : }
494 : :
495 : : void
496 : 30156 : DesugarApit::visit (AST::Function &function)
497 : : {
498 : 30156 : if (!function.has_function_params ())
499 : : return;
500 : :
501 : : auto &fn_params = function.get_function_params ();
502 : 66696 : for (auto ¶m : fn_params)
503 : : {
504 : 42238 : if (param->is_variadic () || param->is_self ())
505 : 42134 : continue;
506 : :
507 : 25208 : auto *p = param.get ();
508 : 25208 : auto &fp = *static_cast<AST::FunctionParam *> (p);
509 : 25208 : auto &type = fp.get_type ();
510 : :
511 : 25208 : auto translated = DesugarApitType::Desugar (type);
512 : 25208 : auto tt = translated.first;
513 : :
514 : 25208 : auto &implicit_generics = translated.second;
515 : 25208 : if (implicit_generics.empty ())
516 : 25104 : continue;
517 : :
518 : 104 : if (fp.get_type_ptr ().get () != tt)
519 : : {
520 : 79 : fp.get_type_ptr () = std::unique_ptr<AST::Type> (tt);
521 : : }
522 : :
523 : 104 : ApitBoundProcessor processor (function.get_where_clause (),
524 : 104 : function.get_generic_params ());
525 : 104 : processor.go (implicit_generics);
526 : 25208 : }
527 : : }
528 : :
529 : : } // namespace AST
530 : : } // namespace Rust
|