Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-clone.h"
20 : : #include "rust-item.h"
21 : :
22 : : namespace Rust {
23 : : namespace AST {
24 : :
25 : : std::unique_ptr<Expr>
26 : 35 : DeriveClone::clone_call (std::unique_ptr<Expr> &&to_clone)
27 : : {
28 : : // $crate::core::clone::Clone::clone for the fully qualified path - we don't
29 : : // link with `core` yet so that might be an issue. Use `Clone::clone` for now?
30 : : // TODO: Factor this function inside the DeriveAccumulator
31 : 35 : auto path = std::unique_ptr<Expr> (
32 : 35 : new PathInExpression (builder.path_in_expression ({"Clone", "clone"})));
33 : :
34 : 35 : auto args = std::vector<std::unique_ptr<Expr>> ();
35 : 35 : args.emplace_back (std::move (to_clone));
36 : :
37 : 35 : return builder.call (std::move (path), std::move (args));
38 : 35 : }
39 : :
40 : : /**
41 : : * Create the actual "clone" function of the implementation, so
42 : : *
43 : : * fn clone(&self) -> Self { <clone_expr> }
44 : : *
45 : : */
46 : : std::unique_ptr<AssociatedItem>
47 : 24 : DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
48 : : {
49 : 24 : auto block = std::unique_ptr<BlockExpr> (
50 : 48 : new BlockExpr ({}, std::move (clone_expr), {}, {}, AST::LoopLabel::error (),
51 : 24 : loc, loc));
52 : 24 : auto big_self_type = builder.single_type_path ("Self");
53 : :
54 : 72 : std::unique_ptr<SelfParam> self (new SelfParam (Lifetime::error (),
55 : 24 : /* is_mut */ false, loc));
56 : :
57 : 24 : std::vector<std::unique_ptr<Param>> params;
58 : 24 : params.push_back (std::move (self));
59 : :
60 : 24 : return std::unique_ptr<AssociatedItem> (
61 : 24 : new Function ({"clone"}, builder.fn_qualifiers (), /* generics */ {},
62 : : /* function params */ std::move (params),
63 : 48 : std::move (big_self_type), WhereClause::create_empty (),
64 : 48 : std::move (block), Visibility::create_private (), {}, loc));
65 : 24 : }
66 : :
67 : : /**
68 : : * Create the Clone trait implementation for a type
69 : : *
70 : : * impl Clone for <type> {
71 : : * <clone_fn>
72 : : * }
73 : : *
74 : : */
75 : : std::unique_ptr<Item>
76 : 24 : DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
77 : : std::string name)
78 : : {
79 : : // should that be `$crate::core::clone::Clone` instead?
80 : 24 : auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
81 : 24 : segments.emplace_back (builder.type_path_segment ("Clone"));
82 : 24 : auto clone = TypePath (std::move (segments), loc);
83 : :
84 : 24 : auto trait_items = std::vector<std::unique_ptr<AssociatedItem>> ();
85 : 24 : trait_items.emplace_back (std::move (clone_fn));
86 : :
87 : 24 : return std::unique_ptr<Item> (
88 : : new TraitImpl (clone, /* unsafe */ false,
89 : : /* exclam */ false, std::move (trait_items),
90 : 48 : /* generics */ {}, builder.single_type_path (name),
91 : 48 : WhereClause::create_empty (), Visibility::create_private (),
92 : 72 : {}, {}, loc));
93 : 24 : }
94 : :
95 : : // TODO: Create new `make_qualified_call` helper function
96 : :
97 : 24 : DeriveClone::DeriveClone (location_t loc)
98 : 24 : : DeriveVisitor (loc), expanded (nullptr)
99 : 24 : {}
100 : :
101 : : std::unique_ptr<AST::Item>
102 : 24 : DeriveClone::go (Item &item)
103 : : {
104 : 24 : item.accept_vis (*this);
105 : :
106 : 24 : rust_assert (expanded);
107 : :
108 : 24 : return std::move (expanded);
109 : : }
110 : :
111 : : void
112 : 7 : DeriveClone::visit_tuple (TupleStruct &item)
113 : : {
114 : 7 : auto cloned_fields = std::vector<std::unique_ptr<Expr>> ();
115 : :
116 : 21 : for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
117 : 14 : cloned_fields.emplace_back (
118 : 28 : clone_call (builder.ref (builder.tuple_idx ("self", idx))));
119 : :
120 : 7 : auto path = std::unique_ptr<Expr> (new PathInExpression (
121 : 14 : builder.path_in_expression ({item.get_identifier ().as_string ()})));
122 : 7 : auto constructor = builder.call (std::move (path), std::move (cloned_fields));
123 : :
124 : 14 : expanded = clone_impl (clone_fn (std::move (constructor)),
125 : 14 : item.get_identifier ().as_string ());
126 : 7 : }
127 : :
128 : : void
129 : 15 : DeriveClone::visit_struct (StructStruct &item)
130 : : {
131 : 15 : if (item.is_unit_struct ())
132 : : {
133 : 1 : auto unit_ctor
134 : 1 : = builder.struct_expr_struct (item.get_struct_name ().as_string ());
135 : 2 : expanded = clone_impl (clone_fn (std::move (unit_ctor)),
136 : 2 : item.get_struct_name ().as_string ());
137 : 1 : return;
138 : 1 : }
139 : :
140 : 14 : auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
141 : 35 : for (auto &field : item.get_fields ())
142 : : {
143 : 21 : auto name = field.get_field_name ().as_string ();
144 : 21 : auto expr = clone_call (
145 : 21 : builder.ref (builder.field_access (builder.identifier ("self"), name)));
146 : :
147 : 21 : cloned_fields.emplace_back (
148 : 42 : builder.struct_expr_field (std::move (name), std::move (expr)));
149 : 21 : }
150 : :
151 : 28 : auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
152 : 28 : std::move (cloned_fields));
153 : 28 : expanded = clone_impl (clone_fn (std::move (ctor)),
154 : 28 : item.get_struct_name ().as_string ());
155 : 14 : }
156 : :
157 : : void
158 : 0 : DeriveClone::visit_enum (Enum &item)
159 : : {
160 : 0 : rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet",
161 : : "Clone");
162 : 0 : }
163 : :
164 : : void
165 : 2 : DeriveClone::visit_union (Union &item)
166 : : {
167 : : // FIXME: Should be $crate::core::clone::AssertParamIsCopy (or similar)
168 : :
169 : : // <Self>
170 : 2 : auto arg = GenericArg::create_type (builder.single_type_path ("Self"));
171 : :
172 : : // AssertParamIsCopy::<Self>
173 : 2 : auto type = std::unique_ptr<TypePathSegment> (
174 : 4 : new TypePathSegmentGeneric (PathIdentSegment ("AssertParamIsCopy", loc),
175 : 8 : false, GenericArgs ({}, {arg}, {}, loc), loc));
176 : 2 : auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> ();
177 : 2 : type_paths.emplace_back (std::move (type));
178 : :
179 : 2 : auto full_path
180 : 2 : = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc));
181 : :
182 : 2 : auto stmts = std::vector<std::unique_ptr<Stmt>> ();
183 : 2 : stmts.emplace_back (
184 : 4 : builder.let (builder.wildcard (), std::move (full_path), nullptr));
185 : 2 : auto tail_expr = builder.deref (builder.identifier ("self"));
186 : :
187 : 2 : auto block = builder.block (std::move (stmts), std::move (tail_expr));
188 : :
189 : 4 : expanded = clone_impl (clone_fn (std::move (block)),
190 : 4 : item.get_identifier ().as_string ());
191 : 2 : }
192 : :
193 : : } // namespace AST
194 : : } // namespace Rust
|