LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-desugar-apit.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 81.9 % 282 231
Test Date: 2026-02-28 14:20:25 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.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 &param : 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
        

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.