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