https://gcc.gnu.org/g:af42d91c9571bf4b95b8939b971244e9eba0828f
commit r16-5602-gaf42d91c9571bf4b95b8939b971244e9eba0828f Author: Philip Herron <[email protected]> Date: Mon Nov 17 21:14:44 2025 +0000 gccrs: Add support for initial generic associated types 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 <[email protected]> Diff: --- gcc/rust/ast/rust-ast.cc | 12 ++++++++ gcc/rust/ast/rust-ast.h | 1 - gcc/rust/ast/rust-item.h | 25 +++++++++++++++-- gcc/rust/ast/rust-type.h | 3 -- gcc/rust/hir/rust-ast-lower-implitem.cc | 32 +++++++++++++++++----- gcc/rust/hir/tree/rust-hir-item.cc | 11 ++++++-- gcc/rust/hir/tree/rust-hir-item.h | 14 ++++++++++ gcc/rust/hir/tree/rust-hir.cc | 12 ++++++++ gcc/rust/parse/rust-parse-impl.h | 12 ++++++-- gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 6 ++++ gcc/rust/typecheck/rust-tyty.cc | 2 +- gcc/testsuite/rust/compile/gat1.rs | 4 +++ gcc/testsuite/rust/execute/torture/gat1.rs | 18 ++++++++++++ 13 files changed, 134 insertions(+), 18 deletions(-) diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index d8713071c4c3..851f7ea4b6f6 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -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 ()) { diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 8a7e618b05ce..8610ade830c1 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -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; diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 7aea763bd12e..3e3735c3ece6 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -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; diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index 014963fb520b..38a34748130e 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -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 { diff --git a/gcc/rust/hir/rust-ast-lower-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc index 8fd9d167cea3..87f1e015321e 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.cc +++ b/gcc/rust/hir/rust-ast-lower-implitem.cc @@ -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 ¶m : 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; diff --git a/gcc/rust/hir/tree/rust-hir-item.cc b/gcc/rust/hir/tree/rust-hir-item.cc index 1406e7aeb515..268b09b1ecaf 100644 --- a/gcc/rust/hir/tree/rust-hir-item.cc +++ b/gcc/rust/hir/tree/rust-hir-item.cc @@ -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 ()); diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index eb9cec741963..76294061d974 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -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; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 57f560b06d3e..614fec7076e1 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -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 ()) { diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 64554f5e9e49..0421d6cb80e5 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -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. diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 83adf2ea761b..8df8a18bddd0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -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); diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 480e244fd38e..5386b72f602f 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -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 index 000000000000..032f64e080ac --- /dev/null +++ b/gcc/testsuite/rust/compile/gat1.rs @@ -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 index 000000000000..8310a5883809 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/gat1.rs @@ -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 +}
