]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Add support for initial generic associated types
authorPhilip Herron <herron.philip@googlemail.com>
Mon, 17 Nov 2025 21:14:44 +0000 (21:14 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 25 Nov 2025 22:00:51 +0000 (23:00 +0100)
This patch is the initial part in supporting generic associated types. In rust we have
trait item types that get implemented for example:

  trait Foo<T> {
    type Bar
  }

  impl<T> Foo for T {
    type Bar = T
  }

The trait position uses a Ty::Placeholder which is just a thing that gets set for
lazy evaluation to the impl type alias which is actually a Ty::Projection see:

  0798add3d3c1bf4b20ecc1b4fa1047ba4ba19759

For more info the projection type needs to hold onto generics in order to properly
support generic types this GAT's support extends this all the way to the placeholder
which still needs to be done.

Fixes Rust-GCC#4276

gcc/rust/ChangeLog:

* ast/rust-ast.cc (TraitItemType::as_string): add generic params
* ast/rust-ast.h: remove old comment
* ast/rust-item.h: add generic params to associated type
* ast/rust-type.h: remove old comment
* hir/rust-ast-lower-implitem.cc (ASTLowerTraitItem::visit): hir lowering for gat's
* hir/tree/rust-hir-item.cc (TraitItemType::TraitItemType): gat's on TraitItemType
(TraitItemType::operator=): preserve generic params
* hir/tree/rust-hir-item.h: likewise
* hir/tree/rust-hir.cc (TraitItemType::as_string): likewise
* parse/rust-parse-impl.h (Parser::parse_trait_type): hit the < and parse params
* typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItemWithTrait::visit): typecheck
* typecheck/rust-tyty.cc (BaseType::has_substitutions_defined): dont destructure

gcc/testsuite/ChangeLog:

* rust/compile/gat1.rs: New test.
* rust/execute/torture/gat1.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
13 files changed:
gcc/rust/ast/rust-ast.cc
gcc/rust/ast/rust-ast.h
gcc/rust/ast/rust-item.h
gcc/rust/ast/rust-type.h
gcc/rust/hir/rust-ast-lower-implitem.cc
gcc/rust/hir/tree/rust-hir-item.cc
gcc/rust/hir/tree/rust-hir-item.h
gcc/rust/hir/tree/rust-hir.cc
gcc/rust/parse/rust-parse-impl.h
gcc/rust/typecheck/rust-hir-type-check-implitem.cc
gcc/rust/typecheck/rust-tyty.cc
gcc/testsuite/rust/compile/gat1.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/gat1.rs [new file with mode: 0644]

index d8713071c4c3d8c7d29d1403555724583393a7e6..851f7ea4b6f6e2d59312629fa978235e62048902 100644 (file)
@@ -3050,6 +3050,18 @@ TraitItemType::as_string () const
 
   str += "\ntype " + name.as_string ();
 
+  if (has_generics ())
+    {
+      str += "<";
+      for (size_t i = 0; i < generic_params.size (); i++)
+       {
+         if (i > 0)
+           str += ", ";
+         str += generic_params[i]->as_string ();
+       }
+      str += ">";
+    }
+
   str += "\n Type param bounds: ";
   if (!has_type_param_bounds ())
     {
index 8a7e618b05ced131200063b76f7ee6ea68d524f1..8610ade830c10778896f28774f00d21f75d3356d 100644 (file)
@@ -1891,7 +1891,6 @@ public:
   {
     parsed_items = std::move (new_items);
   }
-  // TODO: mutable getter seems kinda dodgy
   std::vector<std::unique_ptr<MetaItemInner>> &get_meta_items ()
   {
     return parsed_items;
index 7aea763bd12ee781843234ff469682bc2fa7ae29..3e3735c3ece6ad3bc90021ffd3ac9f9dd227666d 100644 (file)
@@ -2726,21 +2726,28 @@ class TraitItemType : public TraitItem
 
   Identifier name;
 
+  // Generic parameters for GATs (Generic Associated Types)
+  std::vector<std::unique_ptr<GenericParam>> generic_params;
+
   // bool has_type_param_bounds;
   // TypeParamBounds type_param_bounds;
   std::vector<std::unique_ptr<TypeParamBound>>
     type_param_bounds; // inlined form
 
 public:
+  bool has_generics () const { return !generic_params.empty (); }
+
   // Returns whether trait item type has type param bounds.
   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
 
   TraitItemType (Identifier name,
+                std::vector<std::unique_ptr<GenericParam>> generic_params,
                 std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
                 std::vector<Attribute> outer_attrs, Visibility vis,
                 location_t locus)
     : TraitItem (vis, locus), outer_attrs (std::move (outer_attrs)),
-      name (std::move (name)), type_param_bounds (std::move (type_param_bounds))
+      name (std::move (name)), generic_params (std::move (generic_params)),
+      type_param_bounds (std::move (type_param_bounds))
   {}
 
   // Copy constructor with vector clone
@@ -2749,6 +2756,9 @@ public:
       name (other.name)
   {
     node_id = other.node_id;
+    generic_params.reserve (other.generic_params.size ());
+    for (const auto &e : other.generic_params)
+      generic_params.push_back (e->clone_generic_param ());
     type_param_bounds.reserve (other.type_param_bounds.size ());
     for (const auto &e : other.type_param_bounds)
       type_param_bounds.push_back (e->clone_type_param_bound ());
@@ -2763,6 +2773,9 @@ public:
     locus = other.locus;
     node_id = other.node_id;
 
+    generic_params.reserve (other.generic_params.size ());
+    for (const auto &e : other.generic_params)
+      generic_params.push_back (e->clone_generic_param ());
     type_param_bounds.reserve (other.type_param_bounds.size ());
     for (const auto &e : other.type_param_bounds)
       type_param_bounds.push_back (e->clone_type_param_bound ());
@@ -2786,7 +2799,15 @@ public:
   std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
 
-  // TODO: mutable getter seems kinda dodgy
+  std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
+  {
+    return generic_params;
+  }
+  const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
+  {
+    return generic_params;
+  }
+
   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
   {
     return type_param_bounds;
index 014963fb520bb1ddb2e0c2059a2a25bef7eebbc0..38a34748130e53751f6fc1f15b8fc32585584f16 100644 (file)
@@ -177,7 +177,6 @@ public:
 
   void accept_vis (ASTVisitor &vis) override;
 
-  // TODO: mutable getter seems kinda dodgy
   std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds ()
   {
     return type_param_bounds;
@@ -250,7 +249,6 @@ public:
 
   bool is_dyn () const { return has_dyn; }
 
-  // TODO: mutable getter seems kinda dodgy
   std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds ()
   {
     return type_param_bounds;
@@ -463,7 +461,6 @@ public:
 
   void accept_vis (ASTVisitor &vis) override;
 
-  // TODO: mutable getter seems kinda dodgy
   std::vector<std::unique_ptr<Type> > &get_elems () { return elems; }
   const std::vector<std::unique_ptr<Type> > &get_elems () const
   {
index 8fd9d167cea30dc5c2e499787fe34200281cca2f..87f1e015321e58fc5b19d38787d686ab61b6da19 100644 (file)
@@ -55,11 +55,11 @@ ASTLowerImplItem::translate (AST::AssociatedItem &item, HirId parent_impl_id)
 void
 ASTLowerImplItem::visit (AST::TypeAlias &alias)
 {
-  std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
   HIR::WhereClause where_clause (std::move (where_clause_items));
   HIR::Visibility vis = translate_visibility (alias.get_visibility ());
 
-  std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
   if (alias.has_generics ())
     generic_params = lower_generic_params (alias.get_generic_params ());
 
@@ -110,7 +110,7 @@ void
 ASTLowerImplItem::visit (AST::Function &function)
 {
   // ignore for now and leave empty
-  std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
   for (auto &item : function.get_where_clause ().get_items ())
     {
       HIR::WhereClauseItem *i
@@ -124,7 +124,7 @@ ASTLowerImplItem::visit (AST::Function &function)
   HIR::Visibility vis = translate_visibility (function.get_visibility ());
 
   // need
-  std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
   if (function.has_generics ())
     {
       generic_params = lower_generic_params (function.get_generic_params ());
@@ -233,12 +233,12 @@ ASTLowerTraitItem::translate (AST::AssociatedItem &item)
 void
 ASTLowerTraitItem::visit (AST::Function &func)
 {
-  std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+  std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
   HIR::WhereClause where_clause (std::move (where_clause_items));
   HIR::FunctionQualifiers qualifiers
     = lower_qualifiers (func.get_qualifiers ());
 
-  std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
   if (func.has_generics ())
     generic_params = lower_generic_params (func.get_generic_params ());
 
@@ -342,7 +342,24 @@ ASTLowerTraitItem::visit (AST::ConstantItem &constant)
 void
 ASTLowerTraitItem::visit (AST::TraitItemType &type)
 {
-  std::vector<std::unique_ptr<HIR::TypeParamBound> > type_param_bounds;
+  // Lower generic parameters (for GATs)
+  std::vector<std::unique_ptr<HIR::GenericParam>> generic_params;
+  for (auto &param : type.get_generic_params ())
+    {
+      auto lowered_param = ASTLowerGenericParam::translate (*param.get ());
+      generic_params.push_back (
+       std::unique_ptr<HIR::GenericParam> (lowered_param));
+    }
+
+  // Lower type parameter bounds
+  std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
+  for (auto &bound : type.get_type_param_bounds ())
+    {
+      auto lowered_bound = lower_bound (*bound.get ());
+      type_param_bounds.push_back (
+       std::unique_ptr<HIR::TypeParamBound> (lowered_bound));
+    }
+
   auto crate_num = mappings.get_current_crate ();
   Analysis::NodeMapping mapping (crate_num, type.get_node_id (),
                                 mappings.get_next_hir_id (crate_num),
@@ -350,6 +367,7 @@ ASTLowerTraitItem::visit (AST::TraitItemType &type)
 
   HIR::TraitItemType *trait_item
     = new HIR::TraitItemType (mapping, type.get_identifier (),
+                             std::move (generic_params),
                              std::move (type_param_bounds),
                              type.get_outer_attrs (), type.get_locus ());
   translated = trait_item;
index 1406e7aeb51566d724aaff981c48a7ec123fdef8..268b09b1ecafcf774678187550e353510a48d89c 100644 (file)
@@ -716,17 +716,21 @@ TraitItemConst::operator= (TraitItemConst const &other)
 
 TraitItemType::TraitItemType (
   Analysis::NodeMapping mappings, Identifier name,
+  std::vector<std::unique_ptr<GenericParam>> generic_params,
   std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
   AST::AttrVec outer_attrs, location_t locus)
   : TraitItem (mappings), outer_attrs (std::move (outer_attrs)),
-    name (std::move (name)), type_param_bounds (std::move (type_param_bounds)),
-    locus (locus)
+    name (std::move (name)), generic_params (std::move (generic_params)),
+    type_param_bounds (std::move (type_param_bounds)), locus (locus)
 {}
 
 TraitItemType::TraitItemType (TraitItemType const &other)
   : TraitItem (other.mappings), outer_attrs (other.outer_attrs),
     name (other.name), locus (other.locus)
 {
+  generic_params.reserve (other.generic_params.size ());
+  for (const auto &e : other.generic_params)
+    generic_params.push_back (e->clone_generic_param ());
   type_param_bounds.reserve (other.type_param_bounds.size ());
   for (const auto &e : other.type_param_bounds)
     type_param_bounds.push_back (e->clone_type_param_bound ());
@@ -741,6 +745,9 @@ TraitItemType::operator= (TraitItemType const &other)
   locus = other.locus;
   mappings = other.mappings;
 
+  generic_params.reserve (other.generic_params.size ());
+  for (const auto &e : other.generic_params)
+    generic_params.push_back (e->clone_generic_param ());
   type_param_bounds.reserve (other.type_param_bounds.size ());
   for (const auto &e : other.type_param_bounds)
     type_param_bounds.push_back (e->clone_type_param_bound ());
index eb9cec7419636f535bd0416128502d0cc6f6eb3b..76294061d974ba519952024e96832271788cd91a 100644 (file)
@@ -2121,15 +2121,20 @@ class TraitItemType : public TraitItem
   AST::AttrVec outer_attrs;
 
   Identifier name;
+  // Generic parameters for GATs (Generic Associated Types)
+  std::vector<std::unique_ptr<GenericParam>> generic_params;
   std::vector<std::unique_ptr<TypeParamBound>>
     type_param_bounds; // inlined form
   location_t locus;
 
 public:
+  bool has_generics () const { return !generic_params.empty (); }
+
   // Returns whether trait item type has type param bounds.
   bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
 
   TraitItemType (Analysis::NodeMapping mappings, Identifier name,
+                std::vector<std::unique_ptr<GenericParam>> generic_params,
                 std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds,
                 AST::AttrVec outer_attrs, location_t locus);
 
@@ -2152,6 +2157,15 @@ public:
 
   Identifier get_name () const { return name; }
 
+  std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
+  {
+    return generic_params;
+  }
+  const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const
+  {
+    return generic_params;
+  }
+
   std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds ()
   {
     return type_param_bounds;
index 57f560b06d3eb96187b43026654f73bc6b970fd8..614fec7076e15217af2abdf8d3e4ee2836b902a3 100644 (file)
@@ -3582,6 +3582,18 @@ TraitItemType::as_string () const
 
   str += "\ntype " + name.as_string ();
 
+  if (has_generics ())
+    {
+      str += "<";
+      for (size_t i = 0; i < generic_params.size (); i++)
+       {
+         if (i > 0)
+           str += ", ";
+         str += generic_params[i]->as_string ();
+       }
+      str += ">";
+    }
+
   str += "\n Type param bounds: ";
   if (!has_type_param_bounds ())
     {
index 64554f5e9e4919e26f49fe8929d92c8776093dc8..0421d6cb80e56634d638b7f2801a0a33ed4fbed0 100644 (file)
@@ -5221,6 +5221,13 @@ Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
 
   Identifier ident{ident_tok};
 
+  // Parse optional generic parameters for GATs (Generic Associated Types)
+  std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
+  if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
+    {
+      generic_params = parse_generic_params_in_angles ();
+    }
+
   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
 
   // parse optional colon
@@ -5241,8 +5248,9 @@ Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
     }
 
   return std::unique_ptr<AST::TraitItemType> (
-    new AST::TraitItemType (std::move (ident), std::move (bounds),
-                           std::move (outer_attrs), vis, locus));
+    new AST::TraitItemType (std::move (ident), std::move (generic_params),
+                           std::move (bounds), std::move (outer_attrs), vis,
+                           locus));
 }
 
 // Parses a constant trait item.
index 83adf2ea761b50d350f7abd9cd4f1f7b280baf8b..8df8a18bddd06d861d7aad8d4ec340c9b4cba8d5 100644 (file)
@@ -519,6 +519,12 @@ TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant)
 void
 TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type)
 {
+  auto binder_pin = context->push_lifetime_binder ();
+
+  if (type.has_generics ())
+    resolve_generic_params (HIR::Item::ItemKind::TypeAlias, type.get_locus (),
+                           type.get_generic_params (), substitutions);
+
   // normal resolution of the item
   TyTy::BaseType *lookup
     = TypeCheckImplItem::Resolve (parent, type, self, substitutions);
index 480e244fd38e40de12940e78d070d6d8ce98e884..5386b72f602fb1bad295c492d7c2a323e0efcd15 100644 (file)
@@ -890,7 +890,7 @@ BaseType::is_concrete () const
 bool
 BaseType::has_substitutions_defined () const
 {
-  const TyTy::BaseType *x = destructure ();
+  const auto x = this;
   switch (x->get_kind ())
     {
     case INFER:
diff --git a/gcc/testsuite/rust/compile/gat1.rs b/gcc/testsuite/rust/compile/gat1.rs
new file mode 100644 (file)
index 0000000..032f64e
--- /dev/null
@@ -0,0 +1,4 @@
+trait Foo {
+    type Bar<T>;
+    type Baz<'a>;
+}
diff --git a/gcc/testsuite/rust/execute/torture/gat1.rs b/gcc/testsuite/rust/execute/torture/gat1.rs
new file mode 100644 (file)
index 0000000..8310a58
--- /dev/null
@@ -0,0 +1,18 @@
+#[lang = "sized"]
+trait Sized {}
+
+pub struct MyBuf;
+
+trait Foo {
+    type Bar<T>: Sized;
+}
+
+impl Foo for MyBuf {
+    type Bar<T> = T;
+}
+
+type A = <MyBuf as Foo>::Bar<u32>;
+fn main() -> i32 {
+    let a: A = 1;
+    a as i32 - 1
+}