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 : : #ifndef RUST_BIR_BUILDER_PATTERN_H
20 : : #define RUST_BIR_BUILDER_PATTERN_H
21 : :
22 : : #include "rust-bir-builder-internal.h"
23 : : #include "rust-bir-free-region.h"
24 : : #include "rust-tyty-variance-analysis.h"
25 : :
26 : : namespace Rust {
27 : : namespace BIR {
28 : :
29 : : /**
30 : : * Compiles binding of values into newly created variables.
31 : : * Used in let, match arm, and function parameter patterns.
32 : : */
33 : 0 : class PatternBindingBuilder : protected AbstractBuilder,
34 : : public HIR::HIRPatternVisitor
35 : : {
36 : : /** Value of initialization expression. */
37 : : tl::optional<PlaceId> init;
38 : : tl::optional<TyTy::BaseType *> type_annotation;
39 : : tl::optional<FreeRegions> regions;
40 : :
41 : : /** Emulates recursive stack saving and restoring inside a visitor. */
42 : : class SavedState
43 : : {
44 : : PatternBindingBuilder *builder;
45 : :
46 : : public:
47 : : const tl::optional<PlaceId> init;
48 : : const tl::optional<FreeRegions> regions;
49 : :
50 : : public:
51 : 0 : explicit SavedState (PatternBindingBuilder *builder)
52 : 0 : : builder (builder), init (builder->init), regions (builder->regions)
53 : : {}
54 : :
55 : 0 : ~SavedState () { builder->init = init; }
56 : : };
57 : :
58 : : public:
59 : 0 : PatternBindingBuilder (BuilderContext &ctx, tl::optional<PlaceId> init,
60 : : tl::optional<TyTy::BaseType *> type_annotation)
61 : 0 : : AbstractBuilder (ctx), init (init), type_annotation (type_annotation),
62 : 0 : regions (tl::nullopt)
63 : : {}
64 : :
65 : 0 : void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); }
66 : :
67 : 0 : void visit_identifier (const Analysis::NodeMapping &node, bool is_ref,
68 : : bool is_mut = false)
69 : : {
70 : 0 : if (is_ref)
71 : : {
72 : 0 : translated = declare_variable (
73 : : node, new TyTy::ReferenceType (node.get_hirid (),
74 : 0 : TyTy::TyVar (node.get_hirid ()),
75 : : (is_mut) ? Mutability::Mut
76 : 0 : : Mutability::Imm));
77 : : }
78 : : else
79 : : {
80 : 0 : translated = declare_variable (node);
81 : : }
82 : :
83 : 0 : if (init.has_value ())
84 : : {
85 : 0 : push_assignment (translated, init.value ());
86 : : }
87 : 0 : }
88 : :
89 : 0 : void visit (HIR::IdentifierPattern &pattern) override
90 : : {
91 : : // Top-level identifiers are resolved directly to avoid useless temporary
92 : : // (for cleaner BIR).
93 : 0 : visit_identifier (pattern.get_mappings (), pattern.get_is_ref (),
94 : 0 : pattern.is_mut ());
95 : 0 : }
96 : :
97 : 0 : void visit (HIR::ReferencePattern &pattern) override
98 : : {
99 : 0 : SavedState saved (this);
100 : :
101 : 0 : init = init.map ([&] (PlaceId id) {
102 : 0 : return ctx.place_db.lookup_or_add_path (Place::DEREF,
103 : 0 : lookup_type (pattern), id);
104 : : });
105 : :
106 : 0 : type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
107 : 0 : return ty->as<TyTy::ReferenceType> ()->get_base ();
108 : : });
109 : :
110 : 0 : pattern.get_referenced_pattern ()->accept_vis (*this);
111 : 0 : }
112 : :
113 : 0 : void visit (HIR::SlicePattern &pattern) override
114 : : {
115 : 0 : SavedState saved (this);
116 : :
117 : : // All indexes are supposed to point to the same place for borrow-checking.
118 : : // init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type
119 : : // (pattern), saved.init);
120 : 0 : init = init.map ([&] (PlaceId id) {
121 : 0 : return ctx.place_db.lookup_or_add_path (Place::INDEX,
122 : 0 : lookup_type (pattern), id);
123 : : });
124 : :
125 : 0 : type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
126 : 0 : return ty->as<TyTy::SliceType> ()->get_element_type ();
127 : : });
128 : :
129 : : // Regions are unchnaged.
130 : :
131 : 0 : for (auto &item : pattern.get_items ())
132 : : {
133 : 0 : item->accept_vis (*this);
134 : : }
135 : 0 : }
136 : :
137 : 0 : void visit (HIR::AltPattern &pattern) override
138 : : {
139 : 0 : rust_sorry_at (pattern.get_locus (),
140 : : "borrow-checking of alt patterns is not yet implemented");
141 : 0 : }
142 : :
143 : 0 : void visit (HIR::StructPattern &pattern) override
144 : : {
145 : 0 : SavedState saved (this);
146 : :
147 : 0 : auto tyty = ctx.place_db[init.value ()].tyty;
148 : 0 : rust_assert (tyty->get_kind () == TyTy::ADT);
149 : 0 : auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
150 : 0 : rust_assert (adt_ty->is_struct_struct ());
151 : 0 : auto struct_ty = adt_ty->get_variants ().at (0);
152 : :
153 : 0 : for (auto &field :
154 : 0 : pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
155 : : {
156 : 0 : switch (field->get_item_type ())
157 : : {
158 : 0 : case HIR::StructPatternField::TUPLE_PAT: {
159 : 0 : auto tuple
160 : 0 : = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ());
161 : :
162 : 0 : init = init.map ([&] (PlaceId id) {
163 : 0 : return ctx.place_db.lookup_or_add_path (
164 : 0 : Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id,
165 : 0 : tuple->get_index ());
166 : : });
167 : :
168 : 0 : type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
169 : 0 : return ty->as<TyTy::ADTType> ()
170 : 0 : ->get_variants ()
171 : 0 : .at (0)
172 : 0 : ->get_fields ()
173 : 0 : .at (tuple->get_index ())
174 : 0 : ->get_field_type ();
175 : : });
176 : :
177 : 0 : tuple->get_tuple_pattern ()->accept_vis (*this);
178 : 0 : break;
179 : : }
180 : 0 : case HIR::StructPatternField::IDENT_PAT: {
181 : 0 : auto ident_field
182 : 0 : = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ());
183 : 0 : TyTy::StructFieldType *field_ty = nullptr;
184 : 0 : size_t field_index = 0;
185 : 0 : auto ok = struct_ty->lookup_field (
186 : 0 : ident_field->get_identifier ().as_string (), &field_ty,
187 : : &field_index);
188 : 0 : rust_assert (ok);
189 : 0 : init
190 : 0 : = ctx.place_db.lookup_or_add_path (Place::FIELD,
191 : : field_ty->get_field_type (),
192 : 0 : saved.init.value (),
193 : 0 : field_index);
194 : 0 : ident_field->get_pattern ()->accept_vis (*this);
195 : 0 : break;
196 : : }
197 : 0 : case HIR::StructPatternField::IDENT: {
198 : 0 : auto ident_field
199 : 0 : = static_cast<HIR::StructPatternFieldIdent *> (field.get ());
200 : 0 : TyTy::StructFieldType *field_ty = nullptr;
201 : 0 : size_t field_index = 0;
202 : 0 : auto ok = struct_ty->lookup_field (
203 : 0 : ident_field->get_identifier ().as_string (), &field_ty,
204 : : &field_index);
205 : 0 : rust_assert (ok);
206 : 0 : init
207 : 0 : = ctx.place_db.lookup_or_add_path (Place::FIELD,
208 : : field_ty->get_field_type (),
209 : 0 : saved.init.value (),
210 : 0 : field_index);
211 : 0 : visit_identifier (ident_field->get_mappings (),
212 : 0 : ident_field->get_has_ref (),
213 : 0 : ident_field->is_mut ());
214 : 0 : break;
215 : : }
216 : : }
217 : : }
218 : 0 : }
219 : :
220 : 0 : void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields,
221 : : SavedState &saved, size_t &index)
222 : : {
223 : 0 : for (auto &item : fields)
224 : : {
225 : 0 : auto type = lookup_type (*item);
226 : :
227 : 0 : init = init.map ([&] (PlaceId id) {
228 : 0 : return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id,
229 : 0 : index);
230 : : });
231 : :
232 : 0 : type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
233 : 0 : return ty->as<TyTy::TupleType> ()
234 : 0 : ->get_fields ()
235 : 0 : .at (index)
236 : 0 : .get_tyty ();
237 : : });
238 : :
239 : 0 : regions = regions.map ([&] (FreeRegions regs) {
240 : 0 : return bind_regions (Resolver::TypeCheckContext::get ()
241 : 0 : ->get_variance_analysis_ctx ()
242 : 0 : .query_type_regions (type),
243 : 0 : regs);
244 : 0 : });
245 : :
246 : 0 : item->accept_vis (*this);
247 : 0 : index++;
248 : : }
249 : 0 : }
250 : :
251 : 0 : void visit (HIR::TuplePattern &pattern) override
252 : : {
253 : 0 : SavedState saved (this);
254 : :
255 : 0 : size_t index = 0;
256 : 0 : switch (pattern.get_items ()->get_item_type ())
257 : : {
258 : 0 : case HIR::TuplePatternItems::MULTIPLE: {
259 : 0 : auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
260 : 0 : *pattern.get_items ());
261 : 0 : visit_tuple_fields (items.get_patterns (), saved, index);
262 : 0 : break;
263 : : }
264 : 0 : case HIR::TuplePatternItems::RANGED: {
265 : 0 : auto &items = static_cast<HIR::TuplePatternItemsRanged &> (
266 : 0 : *pattern.get_items ());
267 : :
268 : 0 : auto tyty = ctx.place_db[init.value ()].tyty;
269 : 0 : rust_assert (tyty->get_kind () == TyTy::TUPLE);
270 : :
271 : 0 : auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields ()
272 : 0 : - items.get_lower_patterns ().size ()
273 : 0 : - items.get_upper_patterns ().size ();
274 : :
275 : 0 : visit_tuple_fields (items.get_lower_patterns (), saved, index);
276 : 0 : index += skipped;
277 : 0 : visit_tuple_fields (items.get_upper_patterns (), saved, index);
278 : 0 : break;
279 : : }
280 : : }
281 : 0 : init = saved.init;
282 : 0 : }
283 : :
284 : 0 : void visit (HIR::TupleStructPattern &pattern) override
285 : : {
286 : 0 : SavedState saved (this);
287 : :
288 : 0 : type_annotation = tl::nullopt;
289 : :
290 : 0 : auto type = lookup_type (pattern);
291 : :
292 : 0 : regions = regions.map ([&] (FreeRegions regs) {
293 : 0 : return bind_regions (Resolver::TypeCheckContext::get ()
294 : 0 : ->get_variance_analysis_ctx ()
295 : 0 : .query_type_regions (type),
296 : 0 : regs);
297 : 0 : });
298 : :
299 : 0 : size_t index = 0;
300 : 0 : switch (pattern.get_items ()->get_item_type ())
301 : : {
302 : 0 : case HIR::TupleStructItems::RANGED: {
303 : 0 : auto &items
304 : 0 : = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ());
305 : :
306 : 0 : rust_assert (type->get_kind () == TyTy::ADT);
307 : 0 : auto adt_ty = static_cast<TyTy::ADTType *> (type);
308 : 0 : rust_assert (adt_ty->is_tuple_struct ());
309 : :
310 : 0 : auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size ()
311 : 0 : - items.get_lower_patterns ().size ()
312 : 0 : - items.get_upper_patterns ().size ();
313 : :
314 : 0 : visit_tuple_fields (items.get_lower_patterns (), saved, index);
315 : 0 : index += skipped;
316 : 0 : visit_tuple_fields (items.get_upper_patterns (), saved, index);
317 : 0 : break;
318 : : }
319 : 0 : case HIR::TupleStructItems::MULTIPLE: {
320 : 0 : auto &items = static_cast<HIR::TupleStructItemsNoRange &> (
321 : 0 : *pattern.get_items ());
322 : 0 : visit_tuple_fields (items.get_patterns (), saved, index);
323 : 0 : break;
324 : : }
325 : : }
326 : 0 : }
327 : 0 : void visit (HIR::WildcardPattern &pattern) override {}
328 : :
329 : : // Unused for binding.
330 : 0 : void visit (HIR::LiteralPattern &pattern) override {}
331 : 0 : void visit (HIR::PathInExpression &expression) override {}
332 : 0 : void visit (HIR::QualifiedPathInExpression &expression) override {}
333 : 0 : void visit (HIR::RangePattern &pattern) override {}
334 : : };
335 : : } // namespace BIR
336 : : } // namespace Rust
337 : :
338 : : #endif // RUST_BIR_BUILDER_PATTERN_H
|