Line data Source code
1 : // Copyright (C) 2025-2026 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 32130 : 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 16065 : Desugar (AST::Type &type)
33 : {
34 16065 : DesugarApitType visitor (&type);
35 16065 : type.accept_vis (visitor);
36 16065 : rust_assert (visitor.translated != nullptr);
37 16065 : return std::make_pair (visitor.translated,
38 16065 : std::move (visitor.implicit_generic_params));
39 16065 : }
40 :
41 : // Generate a unique impl trait parameter name
42 102 : static Identifier get_impl_name ()
43 : {
44 102 : static size_t counter = 0;
45 204 : return Identifier ("Impl_" + std::to_string (counter++));
46 : }
47 :
48 : // these can hold other types
49 47 : void visit (AST::TupleType &tuple) override
50 : {
51 131 : for (auto &elem : tuple.get_elems ())
52 : {
53 84 : auto &type = *elem.get ();
54 84 : auto desugar = Desugar (type);
55 84 : auto tt = desugar.first;
56 :
57 84 : auto &implicit_generics = desugar.second;
58 84 : if (implicit_generics.empty ())
59 70 : 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 84 : }
67 47 : }
68 :
69 371 : void visit (AST::ArrayType &type) override
70 : {
71 371 : auto &element_type = type.get_element_type ();
72 371 : auto desugar = Desugar (*element_type);
73 371 : auto tt = desugar.first;
74 :
75 371 : auto &implicit_generics = desugar.second;
76 371 : if (implicit_generics.empty ())
77 371 : 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 371 : }
85 :
86 2977 : void visit (AST::ReferenceType &type) override
87 : {
88 : // Get a reference to the current type for in-place modification
89 2977 : auto &referenced_type = type.get_type_referenced ();
90 2977 : auto desugar = Desugar (referenced_type);
91 2977 : auto tt = desugar.first;
92 :
93 2977 : auto &implicit_generics = desugar.second;
94 2977 : if (implicit_generics.empty ())
95 2963 : return;
96 :
97 : // Update the reference type's contents rather than creating a new one
98 14 : if (&referenced_type != tt)
99 : {
100 14 : std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
101 14 : static_cast<AST::TypeNoBounds *> (tt));
102 14 : type.get_type_ptr () = std::move (new_type_no_bounds);
103 14 : }
104 :
105 : // Collect all the implicit generic parameters we found
106 28 : for (auto &implicit_generic : implicit_generics)
107 14 : implicit_generic_params.push_back (std::move (implicit_generic));
108 2977 : }
109 :
110 1705 : void visit (AST::RawPointerType &type) override
111 : {
112 1705 : auto &pointed_type = type.get_type_pointed_to ();
113 1705 : auto desugar = Desugar (pointed_type);
114 1705 : auto tt = desugar.first;
115 :
116 1705 : auto &implicit_generics = desugar.second;
117 1705 : if (implicit_generics.empty ())
118 1705 : 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 1705 : }
132 :
133 232 : void visit (AST::SliceType &type) override
134 : {
135 232 : auto &element_type = type.get_elem_type ();
136 232 : auto desugar = Desugar (element_type);
137 232 : auto tt = desugar.first;
138 :
139 232 : auto &implicit_generics = desugar.second;
140 232 : if (implicit_generics.empty ())
141 232 : 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 232 : }
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 102 : void visit (AST::ImplTraitTypeOneBound &type) override
220 : {
221 : // Generate a unique name using the static method
222 102 : 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 204 : auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ());
227 : // Create a vector of SimplePathSegments for SimplePath constructor
228 204 : std::vector<SimplePathSegment> simple_segs = {simple_seg};
229 : // Create a SimplePath
230 102 : auto simple_path = SimplePath (simple_segs, false, type.get_locus ());
231 :
232 : // Convert to TypePath by creating path segments
233 102 : std::vector<std::unique_ptr<TypePathSegment>> segments;
234 102 : segments.emplace_back (
235 204 : new TypePathSegment (PathIdentSegment (ident.as_string (),
236 204 : type.get_locus ()),
237 204 : false, type.get_locus ()));
238 :
239 : // Create TypePath from segments
240 102 : auto type_path
241 102 : = new TypePath (std::move (segments), type.get_locus (), false);
242 :
243 : // Convert the bound to a generic parameter bound
244 102 : std::vector<std::unique_ptr<TypeParamBound>> bounds;
245 102 : bounds.push_back (std::move (type.get_trait_bound ()));
246 :
247 : // Create the new generic parameter
248 102 : auto generic_param = std::unique_ptr<TypeParam> (
249 : new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {},
250 102 : true /*from impl trait*/));
251 :
252 : // Store the generic parameter to be added to the function signature
253 102 : implicit_generic_params.push_back (std::move (generic_param));
254 :
255 : // Replace impl trait with the new type parameter
256 102 : translated = type_path;
257 102 : }
258 :
259 : private:
260 16065 : DesugarApitType (AST::Type *base)
261 16065 : : 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 168 : class ApitBoundProcessor
271 : {
272 : public:
273 84 : ApitBoundProcessor (
274 : WhereClause &where_clause,
275 : std::vector<std::unique_ptr<GenericParam>> &generic_params)
276 84 : : where_clause (where_clause), generic_params (generic_params)
277 : {}
278 :
279 84 : 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 175 : for (auto &implicit_generic : implicit_generics)
301 : {
302 91 : switch (implicit_generic->get_kind ())
303 : {
304 91 : case GenericParam::Kind::Type:
305 91 : {
306 91 : TypeParam &p
307 91 : = *static_cast<TypeParam *> (implicit_generic.get ());
308 :
309 91 : process_type_param (p);
310 91 : generic_params.push_back (std::move (implicit_generic));
311 102 : for (auto &synth : synthetic_params)
312 11 : generic_params.push_back (std::move (synth));
313 91 : synthetic_params.clear ();
314 : }
315 91 : break;
316 :
317 0 : default:
318 0 : generic_params.push_back (std::move (implicit_generic));
319 0 : break;
320 : }
321 : }
322 84 : }
323 :
324 : private:
325 91 : void process_type_param (TypeParam &p)
326 : {
327 91 : auto &bounds = p.get_type_param_bounds ();
328 91 : std::vector<size_t> bounds_to_remove;
329 182 : for (size_t i = 0; i < bounds.size (); i++)
330 : {
331 91 : auto &tb = bounds[i];
332 91 : switch (tb->get_bound_type ())
333 : {
334 91 : case TypeParamBound::TypeParamBoundType::TRAIT:
335 91 : {
336 91 : TraitBound &ttb = *static_cast<TraitBound *> (tb.get ());
337 91 : TypePath &path = ttb.get_type_path ();
338 91 : bool deusgared = process_type_path (p, ttb, path);
339 91 : if (deusgared)
340 11 : bounds_to_remove.push_back (i);
341 : }
342 :
343 91 : default:
344 91 : break;
345 : }
346 : }
347 102 : for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend ();
348 11 : ++it)
349 11 : bounds.erase (bounds.begin () + *it);
350 91 : }
351 :
352 91 : bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path)
353 : {
354 91 : bool desugared = false;
355 182 : for (auto &segment : path.get_segments ())
356 : {
357 91 : 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 91 : default:
367 91 : break;
368 : }
369 : }
370 91 : 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 4398 : DesugarApit::DesugarApit () {}
488 :
489 : void
490 4398 : DesugarApit::go (AST::Crate &crate)
491 : {
492 4398 : DefaultASTVisitor::visit (crate);
493 4398 : }
494 :
495 : void
496 18039 : DesugarApit::visit (AST::Function &function)
497 : {
498 18039 : if (!function.has_function_params ())
499 : return;
500 :
501 : auto &fn_params = function.get_function_params ();
502 32112 : for (auto ¶m : fn_params)
503 : {
504 19537 : if (param->is_variadic () || param->is_self ())
505 19453 : continue;
506 :
507 10682 : auto *p = param.get ();
508 10682 : auto &fp = *static_cast<AST::FunctionParam *> (p);
509 10682 : auto &type = fp.get_type ();
510 :
511 10682 : auto translated = DesugarApitType::Desugar (type);
512 10682 : auto tt = translated.first;
513 :
514 10682 : auto &implicit_generics = translated.second;
515 10682 : if (implicit_generics.empty ())
516 10598 : continue;
517 :
518 84 : if (fp.get_type_ptr ().get () != tt)
519 : {
520 63 : fp.get_type_ptr () = std::unique_ptr<AST::Type> (tt);
521 : }
522 :
523 84 : ApitBoundProcessor processor (function.get_where_clause (),
524 84 : function.get_generic_params ());
525 84 : processor.go (implicit_generics);
526 10682 : }
527 : }
528 :
529 : } // namespace AST
530 : } // namespace Rust
|