LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-desugar-apit.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 82.0 % 283 232
Test Date: 2026-09-12 16:25:28 Functions: 94.4 % 18 17
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.