// Copyright (C) 2025 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-desugar-apit.h" #include "rust-ast.h" #include "rust-type.h" namespace Rust { namespace AST { class DesugarApitType : public DefaultASTVisitor { using DefaultASTVisitor::visit; public: static std::pair>> Desugar (AST::Type &type) { DesugarApitType visitor (&type); type.accept_vis (visitor); rust_assert (visitor.translated != nullptr); return std::make_pair (visitor.translated, std::move (visitor.implicit_generic_params)); } // Generate a unique impl trait parameter name static Identifier get_impl_name () { static size_t counter = 0; return Identifier ("Impl_" + std::to_string (counter++)); } // these can hold other types void visit (AST::TupleType &tuple) override { for (auto &elem : tuple.get_elems ()) { auto &type = *elem.get (); auto desugar = Desugar (type); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) continue; if (tt != elem.get ()) elem = std::unique_ptr (tt); for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } } void visit (AST::ArrayType &type) override { auto &element_type = type.get_element_type (); auto desugar = Desugar (*element_type); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) return; if (tt != element_type.get ()) element_type = std::unique_ptr (tt); for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } void visit (AST::ReferenceType &type) override { // Get a reference to the current type for in-place modification auto &referenced_type = type.get_type_referenced (); auto desugar = Desugar (referenced_type); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) return; // Update the reference type's contents rather than creating a new one if (&referenced_type != tt) { std::unique_ptr new_type_no_bounds ( static_cast (tt)); type.get_type_ptr () = std::move (new_type_no_bounds); } // Collect all the implicit generic parameters we found for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } void visit (AST::RawPointerType &type) override { auto &pointed_type = type.get_type_pointed_to (); auto desugar = Desugar (pointed_type); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) return; // Update the pointer's inner type directly using the new accessor if (&pointed_type != tt) { std::unique_ptr new_type_no_bounds ( static_cast (tt)); type.get_type_ptr () = std::move (new_type_no_bounds); } // Collect all the implicit generic parameters we found for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } void visit (AST::SliceType &type) override { auto &element_type = type.get_elem_type (); auto desugar = Desugar (element_type); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) return; if (&element_type != tt) { std::unique_ptr new_elem_type (tt); type.get_elem_type_ptr () = std::move (new_elem_type); } // Collect all the implicit generic parameters we found for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } void visit (AST::ParenthesisedType &type) override { auto &inner_type_ptr = type.get_type_in_parens (); auto desugar = Desugar (*inner_type_ptr); auto tt = desugar.first; auto &implicit_generics = desugar.second; if (implicit_generics.empty ()) return; if (inner_type_ptr.get () != tt) { std::unique_ptr new_inner_type (tt); inner_type_ptr = std::move (new_inner_type); } // Collect all the implicit generic parameters we found for (auto &implicit_generic : implicit_generics) implicit_generic_params.push_back (std::move (implicit_generic)); } // this is where the desugar happens void visit (AST::ImplTraitType &type) override { // Generate a unique name using the static method auto ident = get_impl_name (); // Create a type path for the new generic parameter // Create a SimplePathSegment with the identifier string auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); // Create a vector of SimplePathSegments for SimplePath constructor std::vector simple_segs = {simple_seg}; // Create a SimplePath auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); // Convert to TypePath by creating path segments std::vector> segments; segments.push_back (std::unique_ptr (new TypePathSegment ( PathIdentSegment (ident.as_string (), type.get_locus ()), false, type.get_locus ()))); // Create TypePath from segments auto type_path = new TypePath (std::move (segments), type.get_locus (), false); // Convert bounds from impl trait to generic parameter bounds std::vector> bounds; for (auto &bound : type.get_type_param_bounds ()) bounds.push_back (bound->clone_type_param_bound ()); // Create the new generic parameter auto generic_param = std::unique_ptr ( new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, true /*from impl trait*/)); // Store the generic parameter to be added to the function signature implicit_generic_params.push_back (std::move (generic_param)); // Replace impl trait with the new type parameter translated = type_path; } void visit (AST::ImplTraitTypeOneBound &type) override { // Generate a unique name using the static method auto ident = get_impl_name (); // Create a type path for the new generic parameter // Create a SimplePathSegment with the identifier string auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); // Create a vector of SimplePathSegments for SimplePath constructor std::vector simple_segs = {simple_seg}; // Create a SimplePath auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); // Convert to TypePath by creating path segments std::vector> segments; segments.push_back (std::unique_ptr (new TypePathSegment ( PathIdentSegment (ident.as_string (), type.get_locus ()), false, type.get_locus ()))); // Create TypePath from segments auto type_path = new TypePath (std::move (segments), type.get_locus (), false); // Convert the bound to a generic parameter bound std::vector> bounds; bounds.push_back (std::move (type.get_trait_bound ())); // Create the new generic parameter auto generic_param = std::unique_ptr ( new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, true /*from impl trait*/)); // Store the generic parameter to be added to the function signature implicit_generic_params.push_back (std::move (generic_param)); // Replace impl trait with the new type parameter translated = type_path; } private: DesugarApitType (AST::Type *base) : translated (base), implicit_generic_params () {} AST::Type *translated; std::vector> implicit_generic_params; }; // --------- class ApitBoundProcessor { public: ApitBoundProcessor ( WhereClause &where_clause, std::vector> &generic_params) : where_clause (where_clause), generic_params (generic_params) {} void go (std::vector> &implicit_generics) { // some desugars are more complex so imagine this case // // pub fn foo(_value: impl Bar) -> i32 { // 15 // } // // this needs to become: // // pub fn foo(_value: T) -> i32 // where // T: Bar, // U: Foo, // { // 15 // } // // so we need to walk all the implicit generics and the trait bounds paths // for more generics for (auto &implicit_generic : implicit_generics) { switch (implicit_generic->get_kind ()) { case GenericParam::Kind::Type: { TypeParam &p = *static_cast (implicit_generic.get ()); process_type_param (p); generic_params.push_back (std::move (implicit_generic)); for (auto &synth : synthetic_params) generic_params.push_back (std::move (synth)); synthetic_params.clear (); } break; default: generic_params.push_back (std::move (implicit_generic)); break; } } } private: void process_type_param (TypeParam &p) { auto &bounds = p.get_type_param_bounds (); std::vector bounds_to_remove; for (size_t i = 0; i < bounds.size (); i++) { auto &tb = bounds[i]; switch (tb->get_bound_type ()) { case TypeParamBound::TypeParamBoundType::TRAIT: { TraitBound &ttb = *static_cast (tb.get ()); TypePath &path = ttb.get_type_path (); bool deusgared = process_type_path (p, ttb, path); if (deusgared) bounds_to_remove.push_back (i); } default: break; } } for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend (); ++it) bounds.erase (bounds.begin () + *it); } bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path) { bool desugared = false; for (auto &segment : path.get_segments ()) { switch (segment->get_type ()) { case TypePathSegment::SegmentType::GENERIC: { TypePathSegmentGeneric &seg = *static_cast (segment.get ()); desugared |= process_generic_segment (p, parent, path, seg); } default: break; } } return desugared; } bool process_generic_segment (TypeParam &p, TraitBound &parent, TypePath &path, TypePathSegmentGeneric &seg) { // we need to look for any impl types as default arguments in any generics // and remove this index from the generic arguments by using a where // constraint instead std::vector> new_clauses; GenericArgs &generic_args = seg.get_generic_args (); std::vector> bindings_desugared; std::vector &bindings = generic_args.get_binding_args (); for (auto &generic : bindings) { auto &t = generic.get_type (); auto translated = DesugarApitType::Desugar (t); auto tt = translated.first; auto &implicit_generics = translated.second; if (implicit_generics.empty ()) continue; if (tt != &t) { bindings_desugared.push_back (generic); generic.get_type_ptr () = std::unique_ptr (tt); } for (auto &implicit_generic : implicit_generics) { switch (implicit_generic->get_kind ()) { case GenericParam::Kind::Type: { TypeParam &tp = *static_cast (implicit_generic.get ()); std::vector> type_param_bounds; for (auto &b : tp.get_type_param_bounds ()) type_param_bounds.push_back (std::move (b)); tp.get_type_param_bounds ().clear (); // add synthetic parameter for this synthetic_params.push_back (std::move (implicit_generic)); auto bound_type_path = get_type_for_identifier (tp.get_type_representation ()); auto clause = new TypeBoundWhereClauseItem ( {}, std::move (bound_type_path), std::move (type_param_bounds), tp.get_locus ()); std::unique_ptr clause_item = std::unique_ptr (clause); new_clauses.push_back (std::move (clause_item)); } break; default: synthetic_params.push_back (std::move (implicit_generic)); break; } } } std::vector> type_param_bounds; auto bound = std::unique_ptr (new TraitBound (parent)); type_param_bounds.push_back (std::move (bound)); auto parent_type_path = get_type_for_identifier (p.get_type_representation ()); auto clause = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path), std::move (type_param_bounds), parent.get_locus ()); std::unique_ptr clause_item = std::unique_ptr (clause); where_clause.get_items ().push_back (std::move (clause_item)); for (auto &where_item : new_clauses) where_clause.get_items ().push_back (std::move (where_item)); return !bindings_desugared.empty (); } static std::unique_ptr get_type_for_identifier (const Identifier &ident) { auto simple_seg = SimplePathSegment (ident.as_string (), ident.get_locus ()); std::vector simple_segs = {simple_seg}; auto simple_path = SimplePath (simple_segs, false, ident.get_locus ()); std::vector> segments; segments.push_back (std::unique_ptr (new TypePathSegment ( PathIdentSegment (ident.as_string (), ident.get_locus ()), false, ident.get_locus ()))); auto type_path = new TypePath (std::move (segments), ident.get_locus ()); return std::unique_ptr (type_path); } private: WhereClause &where_clause; std::vector> &generic_params; // mutates std::vector> synthetic_params; }; // --------- DesugarApit::DesugarApit () {} void DesugarApit::go (AST::Crate &crate) { DefaultASTVisitor::visit (crate); } void DesugarApit::visit (AST::Function &function) { if (!function.has_function_params ()) return; auto &fn_params = function.get_function_params (); for (auto ¶m : fn_params) { if (param->is_variadic () || param->is_self ()) continue; auto *p = param.get (); auto &fp = *static_cast (p); auto &type = fp.get_type (); auto translated = DesugarApitType::Desugar (type); auto tt = translated.first; auto &implicit_generics = translated.second; if (implicit_generics.empty ()) continue; if (fp.get_type_ptr ().get () != tt) { fp.get_type_ptr () = std::unique_ptr (tt); } ApitBoundProcessor processor (function.get_where_clause (), function.get_generic_params ()); processor.go (implicit_generics); } } } // namespace AST } // namespace Rust