Branch data Line data Source code
1 : : // Copyright (C) 2025 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-derive-eq.h"
20 : : #include "rust-ast.h"
21 : : #include "rust-expr.h"
22 : : #include "rust-item.h"
23 : : #include "rust-path.h"
24 : : #include "rust-pattern.h"
25 : : #include "rust-system.h"
26 : :
27 : : namespace Rust {
28 : : namespace AST {
29 : :
30 : 2 : DeriveEq::DeriveEq (location_t loc) : DeriveVisitor (loc) {}
31 : :
32 : : std::vector<std::unique_ptr<AST::Item>>
33 : 2 : DeriveEq::go (Item &item)
34 : : {
35 : 2 : item.accept_vis (*this);
36 : :
37 : 2 : return std::move (expanded);
38 : : }
39 : :
40 : : std::unique_ptr<AssociatedItem>
41 : 2 : DeriveEq::assert_receiver_is_total_eq_fn (
42 : : std::vector<std::unique_ptr<Type>> &&types)
43 : : {
44 : 2 : auto stmts = std::vector<std::unique_ptr<Stmt>> ();
45 : :
46 : 2 : stmts.emplace_back (assert_param_is_eq ());
47 : :
48 : 4 : for (auto &&type : types)
49 : 2 : stmts.emplace_back (assert_type_is_eq (std::move (type)));
50 : :
51 : 2 : auto block = std::unique_ptr<BlockExpr> (
52 : 2 : new BlockExpr (std::move (stmts), nullptr, {}, {}, tl::nullopt, loc, loc));
53 : :
54 : 2 : auto self = builder.self_ref_param ();
55 : :
56 : 6 : return builder.function ("assert_receiver_is_total_eq",
57 : 6 : vec (std::move (self)), {}, std::move (block));
58 : 2 : }
59 : :
60 : : std::unique_ptr<Stmt>
61 : 2 : DeriveEq::assert_param_is_eq ()
62 : : {
63 : 2 : auto eq_bound = std::unique_ptr<TypeParamBound> (
64 : 2 : new TraitBound (builder.type_path ({"core", "cmp", "Eq"}, true), loc));
65 : :
66 : 2 : auto sized_bound = std::unique_ptr<TypeParamBound> (
67 : 2 : new TraitBound (builder.type_path (LangItem::Kind::SIZED), loc, false,
68 : 2 : true /* opening_question_mark */));
69 : :
70 : 2 : auto bounds = vec (std::move (eq_bound), std::move (sized_bound));
71 : :
72 : 2 : auto assert_param_is_eq = "AssertParamIsEq";
73 : :
74 : 2 : auto t = std::unique_ptr<GenericParam> (
75 : 4 : new TypeParam (Identifier ("T"), loc, std::move (bounds)));
76 : :
77 : 6 : return builder.struct_struct (
78 : 4 : assert_param_is_eq, vec (std::move (t)),
79 : : {StructField (
80 : 6 : Identifier ("_t"),
81 : 4 : builder.single_generic_type_path (
82 : : LangItem::Kind::PHANTOM_DATA,
83 : 2 : GenericArgs (
84 : 6 : {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})),
85 : 6 : Visibility::create_private (), loc)});
86 : 2 : }
87 : :
88 : : std::unique_ptr<Stmt>
89 : 2 : DeriveEq::assert_type_is_eq (std::unique_ptr<Type> &&type)
90 : : {
91 : 2 : auto assert_param_is_eq = "AssertParamIsEq";
92 : :
93 : : // AssertParamIsCopy::<Self>
94 : 2 : auto assert_param_is_eq_ty
95 : : = std::unique_ptr<TypePathSegment> (new TypePathSegmentGeneric (
96 : 4 : PathIdentSegment (assert_param_is_eq, loc), false,
97 : 6 : GenericArgs ({}, {GenericArg::create_type (std::move (type))}, {}, loc),
98 : 4 : loc));
99 : :
100 : : // TODO: Improve this, it's really ugly
101 : 2 : auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> ();
102 : 2 : type_paths.emplace_back (std::move (assert_param_is_eq_ty));
103 : :
104 : 2 : auto full_path
105 : 2 : = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc));
106 : :
107 : 2 : return builder.let (builder.wildcard (), std::move (full_path));
108 : 2 : }
109 : :
110 : : std::vector<std::unique_ptr<Item>>
111 : 2 : DeriveEq::eq_impls (
112 : : std::unique_ptr<AssociatedItem> &&fn, std::string name,
113 : : const std::vector<std::unique_ptr<GenericParam>> &type_generics)
114 : : {
115 : : // We create two copies of the type-path to avoid duplicate NodeIds
116 : 2 : auto eq = builder.type_path ({"core", "cmp", "Eq"}, true);
117 : 2 : auto eq_bound
118 : 2 : = builder.trait_bound (builder.type_path ({"core", "cmp", "Eq"}, true));
119 : :
120 : 2 : auto steq = builder.type_path (LangItem::Kind::STRUCTURAL_TEQ);
121 : :
122 : 2 : auto trait_items = vec (std::move (fn));
123 : :
124 : 2 : auto eq_generics
125 : 2 : = setup_impl_generics (name, type_generics, std::move (eq_bound));
126 : 2 : auto steq_generics = setup_impl_generics (name, type_generics);
127 : :
128 : 4 : auto eq_impl = builder.trait_impl (eq, std::move (eq_generics.self_type),
129 : : std::move (trait_items),
130 : 2 : std::move (eq_generics.impl));
131 : 2 : auto steq_impl
132 : 4 : = builder.trait_impl (steq, std::move (steq_generics.self_type),
133 : : std::move (trait_items),
134 : 2 : std::move (steq_generics.impl));
135 : :
136 : 2 : return vec (std::move (eq_impl), std::move (steq_impl));
137 : 6 : }
138 : :
139 : : void
140 : 2 : DeriveEq::visit_tuple (TupleStruct &item)
141 : : {
142 : 2 : auto types = std::vector<std::unique_ptr<Type>> ();
143 : :
144 : 4 : for (auto &field : item.get_fields ())
145 : 2 : types.emplace_back (field.get_field_type ().clone_type ());
146 : :
147 : 4 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
148 : 2 : item.get_identifier ().as_string (),
149 : 4 : item.get_generic_params ());
150 : 2 : }
151 : :
152 : : void
153 : 0 : DeriveEq::visit_struct (StructStruct &item)
154 : : {
155 : 0 : auto types = std::vector<std::unique_ptr<Type>> ();
156 : :
157 : 0 : for (auto &field : item.get_fields ())
158 : 0 : types.emplace_back (field.get_field_type ().clone_type ());
159 : :
160 : 0 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
161 : 0 : item.get_identifier ().as_string (),
162 : 0 : item.get_generic_params ());
163 : 0 : }
164 : :
165 : : void
166 : 0 : DeriveEq::visit_enum (Enum &item)
167 : : {
168 : 0 : auto types = std::vector<std::unique_ptr<Type>> ();
169 : :
170 : 0 : for (auto &variant : item.get_variants ())
171 : : {
172 : 0 : switch (variant->get_enum_item_kind ())
173 : : {
174 : 0 : case EnumItem::Kind::Identifier:
175 : 0 : case EnumItem::Kind::Discriminant:
176 : : // nothing to do as they contain no inner types
177 : 0 : continue;
178 : 0 : case EnumItem::Kind::Tuple: {
179 : 0 : auto &tuple = static_cast<EnumItemTuple &> (*variant);
180 : :
181 : 0 : for (auto &field : tuple.get_tuple_fields ())
182 : 0 : types.emplace_back (field.get_field_type ().clone_type ());
183 : :
184 : : break;
185 : : }
186 : 0 : case EnumItem::Kind::Struct: {
187 : 0 : auto &tuple = static_cast<EnumItemStruct &> (*variant);
188 : :
189 : 0 : for (auto &field : tuple.get_struct_fields ())
190 : 0 : types.emplace_back (field.get_field_type ().clone_type ());
191 : :
192 : : break;
193 : : }
194 : 0 : }
195 : : }
196 : :
197 : 0 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
198 : 0 : item.get_identifier ().as_string (),
199 : 0 : item.get_generic_params ());
200 : 0 : }
201 : :
202 : : void
203 : 0 : DeriveEq::visit_union (Union &item)
204 : : {
205 : 0 : auto types = std::vector<std::unique_ptr<Type>> ();
206 : :
207 : 0 : for (auto &field : item.get_variants ())
208 : 0 : types.emplace_back (field.get_field_type ().clone_type ());
209 : :
210 : 0 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
211 : 0 : item.get_identifier ().as_string (),
212 : 0 : item.get_generic_params ());
213 : 0 : }
214 : :
215 : : } // namespace AST
216 : : } // namespace Rust
|