Branch data Line data Source code
1 : : // Copyright (C) 2020-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-compile-pattern.h"
20 : : #include "rust-compile-expr.h"
21 : : #include "rust-compile-resolve-path.h"
22 : : #include "rust-constexpr.h"
23 : : #include "rust-compile-type.h"
24 : : #include "print-tree.h"
25 : : #include "rust-diagnostics.h"
26 : : #include "rust-hir-pattern-abstract.h"
27 : : #include "rust-hir-pattern.h"
28 : : #include "rust-system.h"
29 : : #include "rust-tyty.h"
30 : : #include "tree.h"
31 : :
32 : : namespace Rust {
33 : : namespace Compile {
34 : :
35 : : void
36 : 760 : CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern)
37 : : {
38 : : // lookup the type
39 : 760 : TyTy::BaseType *lookup = nullptr;
40 : 760 : bool ok
41 : 760 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
42 : : &lookup);
43 : 760 : rust_assert (ok);
44 : :
45 : : // must be an ADT (?)
46 : 760 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
47 : 760 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
48 : :
49 : : // if this isn't an enum, always succeed
50 : 760 : if (!adt->is_enum ())
51 : : {
52 : 0 : check_expr = boolean_true_node;
53 : 0 : return;
54 : : }
55 : :
56 : : // lookup the variant
57 : 760 : HirId variant_id;
58 : 760 : ok = ctx->get_tyctx ()->lookup_variant_definition (
59 : 760 : pattern.get_mappings ().get_hirid (), &variant_id);
60 : 760 : rust_assert (ok);
61 : :
62 : 760 : TyTy::VariantDef *variant = nullptr;
63 : 760 : ok = adt->lookup_variant_by_id (variant_id, &variant);
64 : 760 : rust_assert (ok);
65 : :
66 : : // find discriminant field of scrutinee
67 : 760 : tree scrutinee_expr_qualifier_expr
68 : 760 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
69 : : pattern.get_locus ());
70 : :
71 : : // must be enum
72 : 760 : match_scrutinee_expr = scrutinee_expr_qualifier_expr;
73 : :
74 : 760 : HIR::Expr &discrim_expr = variant->get_discriminant ();
75 : 760 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
76 : :
77 : 760 : check_expr
78 : 760 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
79 : : match_scrutinee_expr, discrim_expr_node,
80 : : pattern.get_locus ());
81 : : }
82 : :
83 : : void
84 : 393 : CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern)
85 : : {
86 : : // Compile the literal
87 : 393 : auto litexpr = std::make_unique<HIR::LiteralExpr> (
88 : 786 : HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (),
89 : 786 : pattern.get_locus (), std::vector<AST::Attribute> ()));
90 : 393 : if (pattern.get_has_minus ())
91 : 7 : litexpr->set_negative ();
92 : :
93 : : // Note: Floating point literals are currently accepted but will likely be
94 : : // forbidden in LiteralPatterns in a future version of Rust.
95 : : // See: https://github.com/rust-lang/rust/issues/41620
96 : : // For now, we cannot compile them anyway as CASE_LABEL_EXPR does not support
97 : : // floating point types.
98 : 393 : if (pattern.get_literal ().get_lit_type () == HIR::Literal::LitType::FLOAT)
99 : : {
100 : 0 : rust_sorry_at (pattern.get_locus (), "floating-point literal in pattern");
101 : : }
102 : :
103 : 393 : tree lit = CompileExpr::Compile (*litexpr, ctx);
104 : :
105 : 393 : check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL,
106 : : match_scrutinee_expr, lit,
107 : 393 : pattern.get_locus ());
108 : 393 : }
109 : :
110 : : static tree
111 : 76 : compile_range_pattern_bound (HIR::RangePatternBound &bound,
112 : : Analysis::NodeMapping mappings, location_t locus,
113 : : Context *ctx)
114 : : {
115 : 76 : tree result = NULL_TREE;
116 : 76 : switch (bound.get_bound_type ())
117 : : {
118 : 55 : case HIR::RangePatternBound::RangePatternBoundType::LITERAL:
119 : 55 : {
120 : 55 : auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound);
121 : :
122 : 165 : HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus,
123 : 55 : std::vector<AST::Attribute> ());
124 : 55 : if (ref.get_has_minus ())
125 : 25 : litexpr.set_negative ();
126 : :
127 : 55 : result = CompileExpr::Compile (litexpr, ctx);
128 : 55 : }
129 : 55 : break;
130 : :
131 : 21 : case HIR::RangePatternBound::RangePatternBoundType::PATH:
132 : 21 : {
133 : 21 : auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound);
134 : :
135 : 21 : result = ResolvePathRef::Compile (ref.get_path (), ctx);
136 : :
137 : : // If the path resolves to a const expression, fold it.
138 : 21 : result = fold_expr (result);
139 : : }
140 : 21 : break;
141 : :
142 : 0 : case HIR::RangePatternBound::RangePatternBoundType::QUALPATH:
143 : 0 : {
144 : 0 : auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound);
145 : :
146 : 0 : result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx);
147 : :
148 : : // If the path resolves to a const expression, fold it.
149 : 0 : result = fold_expr (result);
150 : : }
151 : : }
152 : :
153 : 76 : return result;
154 : : }
155 : :
156 : : void
157 : 38 : CompilePatternCheckExpr::visit (HIR::RangePattern &pattern)
158 : : {
159 : 38 : tree upper = compile_range_pattern_bound (pattern.get_upper_bound (),
160 : 38 : pattern.get_mappings (),
161 : 38 : pattern.get_locus (), ctx);
162 : 114 : tree lower = compile_range_pattern_bound (pattern.get_lower_bound (),
163 : 38 : pattern.get_mappings (),
164 : 38 : pattern.get_locus (), ctx);
165 : :
166 : 38 : rust_assert (
167 : : (TREE_CODE (upper) == REAL_CST && TREE_CODE (lower) == REAL_CST)
168 : : || (TREE_CODE (upper) == INTEGER_CST && TREE_CODE (lower) == INTEGER_CST));
169 : :
170 : 38 : bool error_E0579 = false;
171 : 38 : if (TREE_CODE (upper) == REAL_CST)
172 : : {
173 : 0 : REAL_VALUE_TYPE upper_r = TREE_REAL_CST (upper);
174 : 0 : REAL_VALUE_TYPE lower_r = TREE_REAL_CST (lower);
175 : 0 : if (real_compare (GE_EXPR, &lower_r, &upper_r))
176 : 0 : error_E0579 = true;
177 : : }
178 : 38 : else if (TREE_CODE (upper) == INTEGER_CST)
179 : : {
180 : 38 : auto upper_wi = wi::to_wide (upper).to_shwi ();
181 : 38 : auto lower_wi = wi::to_wide (lower).to_shwi ();
182 : 38 : if (lower_wi >= upper_wi)
183 : : error_E0579 = true;
184 : : }
185 : :
186 : 0 : if (error_E0579)
187 : 1 : rust_error_at (pattern.get_locus (), ErrorCode::E0579,
188 : : "lower range bound must be less than upper");
189 : :
190 : 38 : ComparisonOperator upper_cmp = pattern.is_inclusive_range ()
191 : 38 : ? ComparisonOperator::LESS_OR_EQUAL
192 : 17 : : ComparisonOperator::LESS_THAN;
193 : 38 : tree check_lower
194 : 38 : = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL,
195 : : match_scrutinee_expr, lower,
196 : 38 : pattern.get_locus ());
197 : 38 : tree check_upper
198 : 38 : = Backend::comparison_expression (upper_cmp, match_scrutinee_expr, upper,
199 : 38 : pattern.get_locus ());
200 : 38 : check_expr = Backend::arithmetic_or_logical_expression (
201 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper,
202 : 38 : pattern.get_locus ());
203 : 38 : }
204 : :
205 : : void
206 : 163 : CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern)
207 : : {
208 : 163 : match_scrutinee_expr
209 : 163 : = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
210 : 163 : pattern.get_referenced_pattern ().accept_vis (*this);
211 : 163 : }
212 : :
213 : : void
214 : 43 : CompilePatternCheckExpr::visit (HIR::AltPattern &pattern)
215 : : {
216 : 43 : auto &alts = pattern.get_alts ();
217 : :
218 : 43 : check_expr = CompilePatternCheckExpr::Compile (*alts.at (0),
219 : : match_scrutinee_expr, ctx);
220 : 43 : auto end = alts.end ();
221 : 87 : for (auto i = alts.begin () + 1; i != end; i++)
222 : : {
223 : 44 : tree next_expr
224 : 44 : = CompilePatternCheckExpr::Compile (**i, match_scrutinee_expr, ctx);
225 : 44 : check_expr = Backend::arithmetic_or_logical_expression (
226 : : ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr,
227 : 44 : (*i)->get_locus ());
228 : : }
229 : 43 : }
230 : :
231 : : void
232 : 127 : CompilePatternCheckExpr::visit (HIR::StructPattern &pattern)
233 : : {
234 : : // lookup the type
235 : 127 : TyTy::BaseType *lookup = nullptr;
236 : 127 : bool ok = ctx->get_tyctx ()->lookup_type (
237 : 127 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
238 : 127 : rust_assert (ok);
239 : :
240 : : // this might be an enum
241 : 127 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
242 : 127 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
243 : :
244 : 127 : rust_assert (adt->number_of_variants () > 0);
245 : 127 : TyTy::VariantDef *variant = nullptr;
246 : 127 : tree variant_accesser_expr = nullptr;
247 : 127 : if (adt->is_enum ())
248 : : {
249 : : // lookup the variant
250 : 111 : HirId variant_id;
251 : 111 : ok = ctx->get_tyctx ()->lookup_variant_definition (
252 : 111 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
253 : 111 : rust_assert (ok);
254 : :
255 : 111 : int variant_index = 0;
256 : 111 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
257 : 111 : rust_assert (ok);
258 : :
259 : : // find expected discriminant
260 : : // // need to access qualifier the field, if we use QUAL_UNION_TYPE this
261 : : // // would be DECL_QUALIFIER i think.
262 : 111 : HIR::Expr &discrim_expr = variant->get_discriminant ();
263 : 111 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
264 : :
265 : : // find discriminant field of scrutinee
266 : 111 : tree scrutinee_expr_qualifier_expr
267 : 111 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
268 : 111 : pattern.get_path ().get_locus ());
269 : :
270 : : // access variant data
271 : 111 : tree scrutinee_union_expr
272 : 111 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
273 : 111 : pattern.get_path ().get_locus ());
274 : 111 : variant_accesser_expr
275 : 111 : = Backend::struct_field_expression (scrutinee_union_expr, variant_index,
276 : 111 : pattern.get_path ().get_locus ());
277 : :
278 : 111 : check_expr
279 : 111 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
280 : : scrutinee_expr_qualifier_expr,
281 : : discrim_expr_node,
282 : 111 : pattern.get_path ().get_locus ());
283 : :
284 : 111 : match_scrutinee_expr = scrutinee_expr_qualifier_expr;
285 : : }
286 : : else
287 : : {
288 : 16 : variant = adt->get_variants ().at (0);
289 : 16 : variant_accesser_expr = match_scrutinee_expr;
290 : 16 : check_expr = boolean_true_node;
291 : : }
292 : :
293 : 127 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
294 : 343 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
295 : : {
296 : 216 : switch (field->get_item_type ())
297 : : {
298 : 0 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
299 : 0 : {
300 : : // TODO
301 : 0 : rust_unreachable ();
302 : : }
303 : 128 : break;
304 : :
305 : 128 : case HIR::StructPatternField::ItemType::IDENT_PAT:
306 : 128 : {
307 : 128 : HIR::StructPatternFieldIdentPat &ident
308 : 128 : = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ());
309 : :
310 : 128 : size_t offs = 0;
311 : 128 : ok = variant->lookup_field (ident.get_identifier ().as_string (),
312 : : nullptr, &offs);
313 : 128 : rust_assert (ok);
314 : :
315 : 128 : tree field_expr
316 : 128 : = Backend::struct_field_expression (variant_accesser_expr, offs,
317 : : ident.get_locus ());
318 : :
319 : 128 : tree check_expr_sub
320 : 128 : = CompilePatternCheckExpr::Compile (ident.get_pattern (),
321 : : field_expr, ctx);
322 : 128 : check_expr = Backend::arithmetic_or_logical_expression (
323 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
324 : 128 : check_expr_sub, ident.get_pattern ().get_locus ());
325 : : }
326 : 128 : break;
327 : :
328 : : case HIR::StructPatternField::ItemType::IDENT:
329 : : {
330 : : // ident pattern always matches - do nothing
331 : : }
332 : : break;
333 : : }
334 : : }
335 : 127 : }
336 : :
337 : : void
338 : 741 : CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
339 : : {
340 : : // lookup the type
341 : 741 : TyTy::BaseType *lookup = nullptr;
342 : 741 : bool ok = ctx->get_tyctx ()->lookup_type (
343 : 741 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
344 : 741 : rust_assert (ok);
345 : :
346 : : // this might be an enum
347 : 741 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
348 : 741 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
349 : :
350 : 741 : int variant_index = 0;
351 : 741 : rust_assert (adt->number_of_variants () > 0);
352 : 741 : TyTy::VariantDef *variant = nullptr;
353 : 741 : if (adt->is_enum ())
354 : : {
355 : : // lookup the variant
356 : 696 : HirId variant_id;
357 : 696 : ok = ctx->get_tyctx ()->lookup_variant_definition (
358 : 696 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
359 : 696 : rust_assert (ok);
360 : :
361 : 696 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
362 : 696 : rust_assert (ok);
363 : :
364 : : // find expected discriminant
365 : 696 : HIR::Expr &discrim_expr = variant->get_discriminant ();
366 : 696 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
367 : :
368 : : // find discriminant field of scrutinee
369 : 696 : tree scrutinee_expr_qualifier_expr
370 : 696 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
371 : 696 : pattern.get_path ().get_locus ());
372 : :
373 : 696 : check_expr
374 : 696 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
375 : : scrutinee_expr_qualifier_expr,
376 : : discrim_expr_node,
377 : 696 : pattern.get_path ().get_locus ());
378 : : }
379 : : else
380 : : {
381 : 45 : variant = adt->get_variants ().at (0);
382 : 45 : check_expr = boolean_true_node;
383 : : }
384 : :
385 : 741 : HIR::TupleStructItems &items = pattern.get_items ();
386 : 741 : switch (items.get_item_type ())
387 : : {
388 : 36 : case HIR::TupleStructItems::HAS_REST:
389 : 36 : {
390 : 36 : HIR::TupleStructItemsHasRest &items_has_rest
391 : : = static_cast<HIR::TupleStructItemsHasRest &> (items);
392 : 36 : size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
393 : 36 : + items_has_rest.get_upper_patterns ().size ();
394 : :
395 : : // enums cases shouldn't reach here
396 : 36 : rust_assert (num_patterns <= variant->num_fields ()
397 : : && (!adt->is_enum ()));
398 : :
399 : 36 : size_t tuple_field_index = 0;
400 : 65 : for (auto &pattern : items_has_rest.get_lower_patterns ())
401 : : {
402 : 29 : tree field_expr
403 : 29 : = Backend::struct_field_expression (match_scrutinee_expr,
404 : : tuple_field_index++,
405 : 29 : pattern->get_locus ());
406 : 29 : tree check_expr_sub
407 : 29 : = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
408 : 29 : check_expr = Backend::arithmetic_or_logical_expression (
409 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
410 : 29 : check_expr_sub, pattern->get_locus ());
411 : : }
412 : 36 : tuple_field_index = variant->num_fields ()
413 : 36 : - items_has_rest.get_upper_patterns ().size ();
414 : 50 : for (auto &pattern : items_has_rest.get_upper_patterns ())
415 : : {
416 : 14 : tree field_expr
417 : 14 : = Backend::struct_field_expression (match_scrutinee_expr,
418 : : tuple_field_index++,
419 : 14 : pattern->get_locus ());
420 : 14 : tree check_expr_sub
421 : 14 : = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
422 : 14 : check_expr = Backend::arithmetic_or_logical_expression (
423 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
424 : 14 : check_expr_sub, pattern->get_locus ());
425 : : }
426 : : }
427 : : break;
428 : :
429 : 705 : case HIR::TupleStructItems::NO_REST:
430 : 705 : {
431 : 705 : HIR::TupleStructItemsNoRest &items_no_range
432 : : = static_cast<HIR::TupleStructItemsNoRest &> (items);
433 : :
434 : 705 : rust_assert (items_no_range.get_patterns ().size ()
435 : : == variant->num_fields ());
436 : :
437 : 705 : if (adt->is_enum ())
438 : : {
439 : 696 : size_t tuple_field_index = 0;
440 : 1472 : for (auto &pattern : items_no_range.get_patterns ())
441 : : {
442 : : // find payload union field of scrutinee
443 : 776 : tree payload_ref
444 : 776 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
445 : 776 : pattern->get_locus ());
446 : :
447 : 776 : tree variant_ref
448 : 776 : = Backend::struct_field_expression (payload_ref,
449 : : variant_index,
450 : 776 : pattern->get_locus ());
451 : :
452 : 776 : tree field_expr
453 : 776 : = Backend::struct_field_expression (variant_ref,
454 : : tuple_field_index++,
455 : 776 : pattern->get_locus ());
456 : :
457 : 776 : tree check_expr_sub
458 : 776 : = CompilePatternCheckExpr::Compile (*pattern, field_expr,
459 : : ctx);
460 : 776 : check_expr = Backend::arithmetic_or_logical_expression (
461 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
462 : 776 : check_expr_sub, pattern->get_locus ());
463 : : }
464 : : }
465 : : else
466 : : {
467 : : // For non-enum TupleStructPatterns
468 : 9 : size_t tuple_field_index = 0;
469 : 26 : for (auto &pattern : items_no_range.get_patterns ())
470 : : {
471 : 17 : tree field_expr
472 : 17 : = Backend::struct_field_expression (match_scrutinee_expr,
473 : : tuple_field_index++,
474 : 17 : pattern->get_locus ());
475 : :
476 : 17 : tree check_expr_sub
477 : 17 : = CompilePatternCheckExpr::Compile (*pattern, field_expr,
478 : : ctx);
479 : 17 : check_expr = Backend::arithmetic_or_logical_expression (
480 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
481 : 17 : check_expr_sub, pattern->get_locus ());
482 : : }
483 : : }
484 : : break;
485 : : }
486 : : }
487 : 741 : }
488 : :
489 : : void
490 : 119 : CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
491 : : {
492 : 119 : check_expr = boolean_true_node;
493 : :
494 : 119 : switch (pattern.get_items ().get_item_type ())
495 : : {
496 : 22 : case HIR::TuplePatternItems::HAS_REST:
497 : 22 : {
498 : 22 : auto &items
499 : 22 : = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
500 : 22 : size_t tuple_field_index = 0;
501 : :
502 : : // lookup the type to find out number of fields
503 : 22 : TyTy::BaseType *ty = nullptr;
504 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (
505 : 22 : pattern.get_mappings ().get_hirid (), &ty);
506 : 22 : rust_assert (ok);
507 : 22 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
508 : :
509 : : // compile check expr for lower patterns
510 : 44 : for (auto &pat : items.get_lower_patterns ())
511 : : {
512 : 22 : tree field_expr
513 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
514 : : tuple_field_index++,
515 : 22 : pat->get_locus ());
516 : :
517 : 22 : tree check_expr_sub
518 : 22 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
519 : 22 : check_expr = Backend::arithmetic_or_logical_expression (
520 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
521 : 22 : check_expr_sub, pat->get_locus ());
522 : : }
523 : :
524 : : // skip the fields that are not checked
525 : 22 : tuple_field_index = static_cast<TyTy::TupleType &> (*ty).num_fields ()
526 : 22 : - items.get_upper_patterns ().size ();
527 : :
528 : : // compile check expr for upper patterns
529 : 44 : for (auto &pat : items.get_upper_patterns ())
530 : : {
531 : 22 : tree field_expr
532 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
533 : : tuple_field_index++,
534 : 22 : pat->get_locus ());
535 : :
536 : 22 : tree check_expr_sub
537 : 22 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
538 : 22 : check_expr = Backend::arithmetic_or_logical_expression (
539 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
540 : 22 : check_expr_sub, pat->get_locus ());
541 : : }
542 : : }
543 : 22 : break;
544 : :
545 : 97 : case HIR::TuplePatternItems::NO_REST:
546 : 97 : {
547 : 97 : auto &items
548 : 97 : = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
549 : 97 : size_t tuple_field_index = 0;
550 : :
551 : 298 : for (auto &pat : items.get_patterns ())
552 : : {
553 : 201 : tree field_expr
554 : 201 : = Backend::struct_field_expression (match_scrutinee_expr,
555 : : tuple_field_index++,
556 : 201 : pat->get_locus ());
557 : :
558 : 201 : tree check_expr_sub
559 : 201 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
560 : 201 : check_expr = Backend::arithmetic_or_logical_expression (
561 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
562 : 201 : check_expr_sub, pat->get_locus ());
563 : : }
564 : : }
565 : : }
566 : 119 : }
567 : :
568 : : void
569 : 712 : CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern)
570 : : {
571 : 712 : if (pattern.has_subpattern ())
572 : : {
573 : 9 : check_expr = CompilePatternCheckExpr::Compile (pattern.get_subpattern (),
574 : : match_scrutinee_expr, ctx);
575 : : }
576 : : else
577 : : {
578 : 703 : check_expr = boolean_true_node;
579 : : }
580 : 712 : }
581 : :
582 : : void
583 : 75 : CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
584 : : {
585 : 75 : check_expr = boolean_true_node;
586 : :
587 : : // lookup the type
588 : 75 : TyTy::BaseType *lookup = nullptr;
589 : 75 : bool ok
590 : 75 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
591 : : &lookup);
592 : 75 : rust_assert (ok);
593 : :
594 : : // pattern must either be ArrayType or SliceType, should be already confirmed
595 : : // by type checking
596 : 75 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
597 : : || lookup->get_kind () == TyTy::TypeKind::SLICE
598 : : || lookup->get_kind () == TyTy::REF);
599 : :
600 : : // function ptr that points to either array_index_expression or
601 : : // slice_index_expression depending on the scrutinee's type
602 : 75 : tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
603 : :
604 : 75 : switch (lookup->get_kind ())
605 : : {
606 : : case TyTy::TypeKind::ARRAY:
607 : : scrutinee_index_expr_func = Backend::array_index_expression;
608 : : break;
609 : 0 : case TyTy::TypeKind::SLICE:
610 : 0 : rust_sorry_at (
611 : : pattern.get_locus (),
612 : : "SlicePattern matching against non-ref slices are not yet supported");
613 : 0 : break;
614 : 39 : case TyTy::TypeKind::REF:
615 : 39 : {
616 : 39 : rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
617 : 39 : scrutinee_index_expr_func = Backend::slice_index_expression;
618 : 39 : tree size_field
619 : 39 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
620 : 39 : pattern.get_locus ());
621 : :
622 : : // for slices, generate a dynamic size comparison expression tree
623 : : // because size checking is done at runtime.
624 : 39 : switch (pattern.get_items ().get_item_type ())
625 : : {
626 : 16 : case HIR::SlicePatternItems::ItemType::NO_REST:
627 : 16 : {
628 : 16 : auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
629 : 16 : pattern.get_items ());
630 : 16 : check_expr = Backend::comparison_expression (
631 : : ComparisonOperator::EQUAL, size_field,
632 : 16 : build_int_cst (size_type_node, items.get_patterns ().size ()),
633 : 16 : pattern.get_locus ());
634 : : }
635 : 16 : break;
636 : 23 : case HIR::SlicePatternItems::ItemType::HAS_REST:
637 : 23 : {
638 : 23 : auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
639 : 23 : pattern.get_items ());
640 : 23 : auto pattern_min_cap = items.get_lower_patterns ().size ()
641 : 23 : + items.get_upper_patterns ().size ();
642 : 23 : check_expr = Backend::comparison_expression (
643 : : ComparisonOperator::GREATER_OR_EQUAL, size_field,
644 : 23 : build_int_cst (size_type_node, pattern_min_cap),
645 : 23 : pattern.get_locus ());
646 : : }
647 : 23 : break;
648 : : }
649 : : }
650 : : break;
651 : 0 : default:
652 : 0 : rust_unreachable ();
653 : : }
654 : :
655 : 39 : rust_assert (scrutinee_index_expr_func != nullptr);
656 : :
657 : : // Generate tree to compare every element within array/slice
658 : 75 : size_t element_index = 0;
659 : 75 : switch (pattern.get_items ().get_item_type ())
660 : : {
661 : 31 : case HIR::SlicePatternItems::ItemType::NO_REST:
662 : 31 : {
663 : 31 : auto &items
664 : 31 : = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
665 : 92 : for (auto &pattern_member : items.get_patterns ())
666 : : {
667 : 61 : tree index_tree
668 : 61 : = Backend::size_constant_expression (element_index++);
669 : 61 : tree element_expr
670 : 61 : = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
671 : 61 : pattern.get_locus ());
672 : 61 : tree check_expr_sub
673 : 61 : = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
674 : : ctx);
675 : 61 : check_expr = Backend::arithmetic_or_logical_expression (
676 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
677 : 61 : check_expr_sub, pattern.get_locus ());
678 : : }
679 : : break;
680 : : }
681 : 44 : case HIR::SlicePatternItems::ItemType::HAS_REST:
682 : 44 : {
683 : 44 : auto &items
684 : 44 : = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
685 : 87 : for (auto &pattern_member : items.get_lower_patterns ())
686 : : {
687 : 43 : tree index_tree
688 : 43 : = Backend::size_constant_expression (element_index++);
689 : 43 : tree element_expr
690 : 43 : = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
691 : 43 : pattern.get_locus ());
692 : 43 : tree check_expr_sub
693 : 43 : = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
694 : : ctx);
695 : 43 : check_expr = Backend::arithmetic_or_logical_expression (
696 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
697 : 43 : check_expr_sub, pattern.get_locus ());
698 : : }
699 : :
700 : : // handle codegen for upper patterns differently for both types
701 : 44 : switch (lookup->get_kind ())
702 : : {
703 : 21 : case TyTy::TypeKind::ARRAY:
704 : 21 : {
705 : : // for array type scrutinee, we can simply get the capacity as a
706 : : // const and calculate how many elements to skip
707 : 21 : auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
708 : 21 : auto capacity_ty = array_ty->get_capacity ();
709 : :
710 : 21 : rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
711 : 21 : auto *capacity_const = capacity_ty->as_const_type ();
712 : 21 : rust_assert (capacity_const->const_kind ()
713 : : == TyTy::BaseConstType::ConstKind::Value);
714 : 21 : auto &capacity_value
715 : : = *static_cast<TyTy::ConstValueType *> (capacity_const);
716 : 21 : auto cap_tree = capacity_value.get_value ();
717 : :
718 : 21 : rust_assert (!error_operand_p (cap_tree));
719 : :
720 : 21 : size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
721 : 21 : element_index = cap_wi - items.get_upper_patterns ().size ();
722 : 42 : for (auto &pattern_member : items.get_upper_patterns ())
723 : : {
724 : 21 : tree index_tree
725 : 21 : = Backend::size_constant_expression (element_index++);
726 : 21 : tree element_expr
727 : 21 : = scrutinee_index_expr_func (match_scrutinee_expr,
728 : : index_tree,
729 : 21 : pattern.get_locus ());
730 : 21 : tree check_expr_sub
731 : 21 : = CompilePatternCheckExpr::Compile (*pattern_member,
732 : : element_expr, ctx);
733 : 21 : check_expr = Backend::arithmetic_or_logical_expression (
734 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
735 : 21 : check_expr_sub, pattern.get_locus ());
736 : : }
737 : : }
738 : : break;
739 : 23 : case TyTy::TypeKind::REF:
740 : 23 : {
741 : : // for slice type scrutinee, size is dyanamic, so number of
742 : : // elements to skip is calculated during runtime
743 : 23 : tree slice_size
744 : 23 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
745 : 23 : pattern.get_locus ());
746 : 23 : tree upper_patterns_size = Backend::size_constant_expression (
747 : 23 : items.get_upper_patterns ().size ());
748 : 23 : tree index_tree = Backend::arithmetic_or_logical_expression (
749 : : ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
750 : 23 : upper_patterns_size, pattern.get_locus ());
751 : 45 : for (auto &pattern_member : items.get_upper_patterns ())
752 : : {
753 : 22 : tree element_expr
754 : 22 : = scrutinee_index_expr_func (match_scrutinee_expr,
755 : : index_tree,
756 : 22 : pattern.get_locus ());
757 : 22 : tree check_expr_sub
758 : 22 : = CompilePatternCheckExpr::Compile (*pattern_member,
759 : : element_expr, ctx);
760 : 22 : check_expr = Backend::arithmetic_or_logical_expression (
761 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
762 : 22 : check_expr_sub, pattern.get_locus ());
763 : 22 : index_tree = Backend::arithmetic_or_logical_expression (
764 : : ArithmeticOrLogicalOperator::ADD, index_tree,
765 : : Backend::size_constant_expression (1),
766 : 22 : pattern.get_locus ());
767 : : }
768 : : }
769 : : break;
770 : 0 : default:
771 : 0 : rust_unreachable ();
772 : : }
773 : : }
774 : : break;
775 : : }
776 : 75 : }
777 : :
778 : : // setup the bindings
779 : :
780 : : void
781 : 727 : CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
782 : : {
783 : : // lookup the type
784 : 727 : TyTy::BaseType *lookup = nullptr;
785 : 727 : bool ok = ctx->get_tyctx ()->lookup_type (
786 : 727 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
787 : 727 : rust_assert (ok);
788 : :
789 : : // this must be an enum
790 : 727 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
791 : 727 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
792 : 727 : rust_assert (adt->number_of_variants () > 0);
793 : :
794 : 727 : int variant_index = 0;
795 : 727 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
796 : 727 : if (adt->is_enum ())
797 : : {
798 : 668 : HirId variant_id = UNKNOWN_HIRID;
799 : 668 : bool ok = ctx->get_tyctx ()->lookup_variant_definition (
800 : 668 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
801 : 668 : rust_assert (ok);
802 : :
803 : 668 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
804 : 668 : rust_assert (ok);
805 : : }
806 : :
807 : 727 : rust_assert (variant->get_variant_type ()
808 : : == TyTy::VariantDef::VariantType::TUPLE);
809 : :
810 : 727 : HIR::TupleStructItems &items = pattern.get_items ();
811 : 727 : switch (items.get_item_type ())
812 : : {
813 : 36 : case HIR::TupleStructItems::HAS_REST:
814 : 36 : {
815 : 36 : HIR::TupleStructItemsHasRest &items_has_rest
816 : : = static_cast<HIR::TupleStructItemsHasRest &> (items);
817 : 36 : size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
818 : 36 : + items_has_rest.get_upper_patterns ().size ();
819 : :
820 : : // enums cases shouldn't reach here
821 : 36 : rust_assert (num_patterns <= variant->num_fields ()
822 : : && (!adt->is_enum ()));
823 : :
824 : 36 : size_t tuple_field_index = 0;
825 : 65 : for (auto &pattern : items_has_rest.get_lower_patterns ())
826 : : {
827 : 29 : tree binding
828 : 29 : = Backend::struct_field_expression (match_scrutinee_expr,
829 : : tuple_field_index++,
830 : 29 : pattern->get_locus ());
831 : :
832 : 29 : CompilePatternBindings::Compile (*pattern, binding, ctx);
833 : : }
834 : :
835 : 36 : tuple_field_index = variant->num_fields ()
836 : 36 : - items_has_rest.get_upper_patterns ().size ();
837 : :
838 : 50 : for (auto &pattern : items_has_rest.get_upper_patterns ())
839 : : {
840 : 14 : tree binding
841 : 14 : = Backend::struct_field_expression (match_scrutinee_expr,
842 : : tuple_field_index++,
843 : 14 : pattern->get_locus ());
844 : :
845 : 14 : CompilePatternBindings::Compile (*pattern, binding, ctx);
846 : : }
847 : : }
848 : : break;
849 : :
850 : 691 : case HIR::TupleStructItems::NO_REST:
851 : 691 : {
852 : 691 : HIR::TupleStructItemsNoRest &items_no_rest
853 : : = static_cast<HIR::TupleStructItemsNoRest &> (items);
854 : 691 : rust_assert (items_no_rest.get_patterns ().size ()
855 : : == variant->num_fields ());
856 : :
857 : 691 : if (adt->is_enum ())
858 : : {
859 : 668 : size_t tuple_field_index = 0;
860 : 1416 : for (auto &pattern : items_no_rest.get_patterns ())
861 : : {
862 : 748 : tree payload_accessor_union
863 : 748 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
864 : 748 : pattern->get_locus ());
865 : :
866 : 748 : tree variant_accessor
867 : 748 : = Backend::struct_field_expression (payload_accessor_union,
868 : : variant_index,
869 : 748 : pattern->get_locus ());
870 : :
871 : 748 : tree binding
872 : 748 : = Backend::struct_field_expression (variant_accessor,
873 : : tuple_field_index++,
874 : 748 : pattern->get_locus ());
875 : :
876 : 748 : CompilePatternBindings::Compile (*pattern, binding, ctx);
877 : : }
878 : : }
879 : : else
880 : : {
881 : 23 : size_t tuple_field_index = 0;
882 : 61 : for (auto &pattern : items_no_rest.get_patterns ())
883 : : {
884 : 38 : tree binding
885 : 38 : = Backend::struct_field_expression (match_scrutinee_expr,
886 : : tuple_field_index++,
887 : 38 : pattern->get_locus ());
888 : :
889 : 38 : CompilePatternBindings::Compile (*pattern, binding, ctx);
890 : : }
891 : : }
892 : : }
893 : : break;
894 : : }
895 : 727 : }
896 : :
897 : : tree
898 : 216 : CompilePatternBindings::make_struct_access (TyTy::ADTType *adt,
899 : : TyTy::VariantDef *variant,
900 : : const Identifier &ident,
901 : : int variant_index)
902 : : {
903 : 216 : size_t offs = 0;
904 : 216 : auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs);
905 : 216 : rust_assert (ok);
906 : :
907 : 216 : if (adt->is_enum ())
908 : : {
909 : 187 : tree payload_accessor_union
910 : 187 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
911 : : ident.get_locus ());
912 : :
913 : 187 : tree variant_accessor
914 : 187 : = Backend::struct_field_expression (payload_accessor_union,
915 : : variant_index, ident.get_locus ());
916 : :
917 : 187 : return Backend::struct_field_expression (variant_accessor, offs,
918 : 187 : ident.get_locus ());
919 : : }
920 : : else
921 : : {
922 : 29 : tree variant_accessor = match_scrutinee_expr;
923 : :
924 : 29 : return Backend::struct_field_expression (variant_accessor, offs,
925 : 29 : ident.get_locus ());
926 : : }
927 : : }
928 : :
929 : : void
930 : 88 : CompilePatternBindings::handle_struct_pattern_ident (
931 : : HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
932 : : int variant_index)
933 : : {
934 : 88 : HIR::StructPatternFieldIdent &ident
935 : : = static_cast<HIR::StructPatternFieldIdent &> (pat);
936 : :
937 : 88 : auto identifier = ident.get_identifier ();
938 : 88 : tree binding = make_struct_access (adt, variant, identifier, variant_index);
939 : :
940 : 88 : ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding);
941 : 88 : }
942 : :
943 : : void
944 : 128 : CompilePatternBindings::handle_struct_pattern_ident_pat (
945 : : HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
946 : : int variant_index)
947 : : {
948 : 128 : auto &pattern = static_cast<HIR::StructPatternFieldIdentPat &> (pat);
949 : :
950 : 128 : tree binding = make_struct_access (adt, variant, pattern.get_identifier (),
951 : : variant_index);
952 : 128 : CompilePatternBindings::Compile (pattern.get_pattern (), binding, ctx);
953 : 128 : }
954 : :
955 : : void
956 : 0 : CompilePatternBindings::handle_struct_pattern_tuple_pat (
957 : : HIR::StructPatternField &pat)
958 : : {
959 : 0 : rust_unreachable ();
960 : : }
961 : :
962 : : void
963 : 127 : CompilePatternBindings::visit (HIR::StructPattern &pattern)
964 : : {
965 : : // lookup the type
966 : 127 : TyTy::BaseType *lookup = nullptr;
967 : 127 : bool ok = ctx->get_tyctx ()->lookup_type (
968 : 127 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
969 : 127 : rust_assert (ok);
970 : :
971 : : // this must be an enum
972 : 127 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
973 : 127 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
974 : 127 : rust_assert (adt->number_of_variants () > 0);
975 : :
976 : 127 : int variant_index = 0;
977 : 127 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
978 : 127 : if (adt->is_enum ())
979 : : {
980 : 111 : HirId variant_id = UNKNOWN_HIRID;
981 : 111 : bool ok = ctx->get_tyctx ()->lookup_variant_definition (
982 : 111 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
983 : 111 : rust_assert (ok);
984 : :
985 : 111 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
986 : 111 : rust_assert (ok);
987 : : }
988 : :
989 : 127 : rust_assert (
990 : : variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT
991 : : || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE);
992 : :
993 : 127 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
994 : 343 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
995 : : {
996 : 216 : switch (field->get_item_type ())
997 : : {
998 : 0 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
999 : 0 : handle_struct_pattern_tuple_pat (*field);
1000 : 0 : break;
1001 : 128 : case HIR::StructPatternField::ItemType::IDENT_PAT:
1002 : 128 : handle_struct_pattern_ident_pat (*field, adt, variant, variant_index);
1003 : 128 : break;
1004 : 88 : case HIR::StructPatternField::ItemType::IDENT:
1005 : 88 : handle_struct_pattern_ident (*field, adt, variant, variant_index);
1006 : 88 : break;
1007 : : }
1008 : : }
1009 : 127 : }
1010 : :
1011 : : void
1012 : 193 : CompilePatternBindings::visit (HIR::ReferencePattern &pattern)
1013 : : {
1014 : 193 : tree derefed
1015 : 193 : = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
1016 : :
1017 : 193 : CompilePatternBindings::Compile (pattern.get_referenced_pattern (), derefed,
1018 : : ctx);
1019 : 193 : }
1020 : :
1021 : : void
1022 : 794 : CompilePatternBindings::visit (HIR::IdentifierPattern &pattern)
1023 : : {
1024 : 794 : if (pattern.has_subpattern ())
1025 : : {
1026 : 9 : CompilePatternBindings::Compile (pattern.get_subpattern (),
1027 : : match_scrutinee_expr, ctx);
1028 : : }
1029 : :
1030 : 794 : if (!pattern.get_is_ref ())
1031 : : {
1032 : 793 : ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (),
1033 : : match_scrutinee_expr);
1034 : 793 : return;
1035 : : }
1036 : :
1037 : 1 : tree ref = address_expression (match_scrutinee_expr,
1038 : 1 : EXPR_LOCATION (match_scrutinee_expr));
1039 : 1 : ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), ref);
1040 : : }
1041 : :
1042 : : void
1043 : 120 : CompilePatternBindings::visit (HIR::TuplePattern &pattern)
1044 : : {
1045 : 120 : rust_assert (pattern.has_tuple_pattern_items ());
1046 : :
1047 : : // lookup the type
1048 : 120 : TyTy::BaseType *ty = nullptr;
1049 : 120 : bool ok
1050 : 120 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
1051 : : &ty);
1052 : 120 : rust_assert (ok);
1053 : :
1054 : 120 : switch (pattern.get_items ().get_item_type ())
1055 : : {
1056 : 22 : case HIR::TuplePatternItems::ItemType::HAS_REST:
1057 : 22 : {
1058 : 22 : size_t tuple_idx = 0;
1059 : 22 : auto &items
1060 : 22 : = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
1061 : :
1062 : 22 : auto &items_lower = items.get_lower_patterns ();
1063 : 22 : auto &items_upper = items.get_upper_patterns ();
1064 : :
1065 : 44 : for (auto &sub : items_lower)
1066 : : {
1067 : 22 : TyTy::BaseType *ty_sub = nullptr;
1068 : 22 : HirId sub_id = sub->get_mappings ().get_hirid ();
1069 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1070 : 22 : rust_assert (ok);
1071 : :
1072 : 22 : tree sub_init
1073 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
1074 : 22 : tuple_idx, sub->get_locus ());
1075 : :
1076 : 22 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
1077 : 22 : tuple_idx++;
1078 : : }
1079 : :
1080 : 22 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
1081 : 22 : tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
1082 : 22 : - items_upper.size ();
1083 : :
1084 : 44 : for (auto &sub : items_upper)
1085 : : {
1086 : 22 : TyTy::BaseType *ty_sub = nullptr;
1087 : 22 : HirId sub_id = sub->get_mappings ().get_hirid ();
1088 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1089 : 22 : rust_assert (ok);
1090 : :
1091 : 22 : tree sub_init
1092 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
1093 : 22 : tuple_idx, sub->get_locus ());
1094 : 22 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
1095 : 22 : tuple_idx++;
1096 : : }
1097 : :
1098 : : return;
1099 : : }
1100 : 98 : case HIR::TuplePatternItems::ItemType::NO_REST:
1101 : 98 : {
1102 : 98 : size_t tuple_idx = 0;
1103 : 98 : auto &items
1104 : 98 : = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
1105 : :
1106 : 301 : for (auto &sub : items.get_patterns ())
1107 : : {
1108 : 203 : TyTy::BaseType *ty_sub = nullptr;
1109 : 203 : HirId sub_id = sub->get_mappings ().get_hirid ();
1110 : 203 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1111 : 203 : rust_assert (ok);
1112 : :
1113 : 203 : tree sub_init
1114 : 203 : = Backend::struct_field_expression (match_scrutinee_expr,
1115 : 203 : tuple_idx, sub->get_locus ());
1116 : 203 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
1117 : 203 : tuple_idx++;
1118 : : }
1119 : :
1120 : : return;
1121 : : }
1122 : 0 : default:
1123 : 0 : {
1124 : 0 : rust_unreachable ();
1125 : : }
1126 : : }
1127 : : }
1128 : :
1129 : : void
1130 : 75 : CompilePatternBindings::visit (HIR::SlicePattern &pattern)
1131 : : {
1132 : : // lookup the type
1133 : 75 : TyTy::BaseType *lookup = nullptr;
1134 : 75 : bool ok
1135 : 75 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
1136 : : &lookup);
1137 : 75 : rust_assert (ok);
1138 : :
1139 : 75 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
1140 : : || lookup->get_kind () == TyTy::TypeKind::SLICE
1141 : : || lookup->get_kind () == TyTy::REF);
1142 : :
1143 : : // function ptr that points to either array_index_expression or
1144 : : // slice_index_expression depending on the scrutinee's type
1145 : 75 : tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
1146 : :
1147 : 75 : switch (lookup->get_kind ())
1148 : : {
1149 : : case TyTy::TypeKind::ARRAY:
1150 : : scrutinee_index_expr_func = Backend::array_index_expression;
1151 : : break;
1152 : 0 : case TyTy::TypeKind::SLICE:
1153 : 0 : rust_sorry_at (pattern.get_locus (),
1154 : : "SlicePattern matching against non-ref slices are "
1155 : : "not yet supported");
1156 : 0 : break;
1157 : : case TyTy::TypeKind::REF:
1158 : : scrutinee_index_expr_func = Backend::slice_index_expression;
1159 : : break;
1160 : 0 : default:
1161 : 0 : rust_unreachable ();
1162 : : }
1163 : :
1164 : 0 : rust_assert (scrutinee_index_expr_func != nullptr);
1165 : :
1166 : 75 : size_t element_index = 0;
1167 : :
1168 : 75 : switch (pattern.get_items ().get_item_type ())
1169 : : {
1170 : 31 : case HIR::SlicePatternItems::ItemType::NO_REST:
1171 : 31 : {
1172 : 31 : auto &items
1173 : 31 : = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
1174 : 92 : for (auto &pattern_member : items.get_patterns ())
1175 : : {
1176 : 61 : tree index_tree
1177 : 61 : = Backend::size_constant_expression (element_index++);
1178 : 61 : tree element_expr
1179 : 61 : = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1180 : 61 : pattern.get_locus ());
1181 : 61 : CompilePatternBindings::Compile (*pattern_member, element_expr,
1182 : : ctx);
1183 : : }
1184 : : }
1185 : : break;
1186 : 44 : case HIR::SlicePatternItems::ItemType::HAS_REST:
1187 : 44 : {
1188 : 44 : auto &items
1189 : 44 : = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
1190 : 87 : for (auto &pattern_member : items.get_lower_patterns ())
1191 : : {
1192 : 43 : tree index_tree
1193 : 43 : = Backend::size_constant_expression (element_index++);
1194 : 43 : tree element_expr
1195 : 43 : = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1196 : 43 : pattern.get_locus ());
1197 : 43 : CompilePatternBindings::Compile (*pattern_member, element_expr,
1198 : : ctx);
1199 : : }
1200 : :
1201 : : // handle codegen for upper patterns differently for both types
1202 : 44 : switch (lookup->get_kind ())
1203 : : {
1204 : 21 : case TyTy::TypeKind::ARRAY:
1205 : 21 : {
1206 : 21 : auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
1207 : 21 : auto capacity_ty = array_ty->get_capacity ();
1208 : :
1209 : 21 : rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
1210 : 21 : auto *capacity_const = capacity_ty->as_const_type ();
1211 : 21 : rust_assert (capacity_const->const_kind ()
1212 : : == TyTy::BaseConstType::ConstKind::Value);
1213 : 21 : auto &capacity_value
1214 : : = *static_cast<TyTy::ConstValueType *> (capacity_const);
1215 : 21 : auto cap_tree = capacity_value.get_value ();
1216 : :
1217 : 21 : rust_assert (!error_operand_p (cap_tree));
1218 : :
1219 : 21 : size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
1220 : 21 : element_index = cap_wi - items.get_upper_patterns ().size ();
1221 : 42 : for (auto &pattern_member : items.get_upper_patterns ())
1222 : : {
1223 : 21 : tree index_tree
1224 : 21 : = Backend::size_constant_expression (element_index++);
1225 : 21 : tree element_expr
1226 : 21 : = scrutinee_index_expr_func (match_scrutinee_expr,
1227 : : index_tree,
1228 : 21 : pattern.get_locus ());
1229 : 21 : CompilePatternBindings::Compile (*pattern_member,
1230 : : element_expr, ctx);
1231 : : }
1232 : : }
1233 : : break;
1234 : 0 : case TyTy::TypeKind::SLICE:
1235 : 0 : rust_sorry_at (pattern.get_locus (),
1236 : : "SlicePattern matching against non-ref slices are "
1237 : : "not yet supported");
1238 : 0 : break;
1239 : 23 : case TyTy::TypeKind::REF:
1240 : 23 : {
1241 : 23 : tree slice_size
1242 : 23 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
1243 : 23 : pattern.get_locus ());
1244 : 23 : tree upper_patterns_size = Backend::size_constant_expression (
1245 : 23 : items.get_upper_patterns ().size ());
1246 : 23 : tree index_tree = Backend::arithmetic_or_logical_expression (
1247 : : ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
1248 : 23 : upper_patterns_size, pattern.get_locus ());
1249 : 45 : for (auto &pattern_member : items.get_upper_patterns ())
1250 : : {
1251 : 22 : tree element_expr
1252 : 22 : = scrutinee_index_expr_func (match_scrutinee_expr,
1253 : : index_tree,
1254 : 22 : pattern.get_locus ());
1255 : 22 : CompilePatternBindings::Compile (*pattern_member,
1256 : : element_expr, ctx);
1257 : 22 : index_tree = Backend::arithmetic_or_logical_expression (
1258 : : ArithmeticOrLogicalOperator::ADD, index_tree,
1259 : : Backend::size_constant_expression (1),
1260 : 22 : pattern.get_locus ());
1261 : : }
1262 : : }
1263 : : break;
1264 : 0 : default:
1265 : 0 : rust_unreachable ();
1266 : : }
1267 : : }
1268 : : break;
1269 : : }
1270 : 75 : }
1271 : :
1272 : : //
1273 : :
1274 : : void
1275 : 11085 : CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
1276 : : {
1277 : 11085 : Bvariable *var = nullptr;
1278 : 11085 : rust_assert (
1279 : : ctx->lookup_var_decl (pattern.get_mappings ().get_hirid (), &var));
1280 : :
1281 : 11085 : if (pattern.get_is_ref ())
1282 : : {
1283 : 1 : init_expr = address_expression (init_expr, EXPR_LOCATION (init_expr));
1284 : : }
1285 : :
1286 : 11085 : auto fnctx = ctx->peek_fn ();
1287 : 11085 : if (ty->is_unit ())
1288 : : {
1289 : 237 : ctx->add_statement (init_expr);
1290 : :
1291 : 237 : auto unit_type_init_expr = unit_expression (rval_locus);
1292 : 237 : auto s = Backend::init_statement (fnctx.fndecl, var, unit_type_init_expr);
1293 : 237 : ctx->add_statement (s);
1294 : : }
1295 : : else
1296 : : {
1297 : 10848 : if (pattern.has_subpattern ())
1298 : : {
1299 : 7 : CompilePatternLet::Compile (&pattern.get_subpattern (), init_expr, ty,
1300 : : rval_locus, ctx);
1301 : : }
1302 : 10848 : auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
1303 : 10848 : ctx->add_statement (s);
1304 : : }
1305 : 11085 : }
1306 : :
1307 : : void
1308 : 203 : CompilePatternLet::visit (HIR::WildcardPattern &pattern)
1309 : : {
1310 : 203 : tree init_stmt = NULL;
1311 : 203 : tree stmt_type = TyTyResolveCompile::compile (ctx, ty);
1312 : :
1313 : 203 : Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, stmt_type,
1314 : 203 : init_expr, false, pattern.get_locus (),
1315 : : &init_stmt);
1316 : :
1317 : 203 : ctx->add_statement (init_stmt);
1318 : 203 : }
1319 : :
1320 : : void
1321 : 288 : CompilePatternLet::visit (HIR::TuplePattern &pattern)
1322 : : {
1323 : 288 : rust_assert (pattern.has_tuple_pattern_items ());
1324 : :
1325 : 288 : bool has_by_ref = false;
1326 : 288 : auto check_refs
1327 : 290 : = [] (const std::vector<std::unique_ptr<HIR::Pattern>> &patterns) {
1328 : 876 : for (const auto &sub : patterns)
1329 : : {
1330 : 587 : switch (sub->get_pattern_type ())
1331 : : {
1332 : 571 : case HIR::Pattern::PatternType::IDENTIFIER:
1333 : 571 : {
1334 : 571 : auto id = static_cast<HIR::IdentifierPattern *> (sub.get ());
1335 : 571 : if (id->get_is_ref ())
1336 : : return true;
1337 : : break;
1338 : : }
1339 : : case HIR::Pattern::PatternType::REFERENCE:
1340 : : return true;
1341 : : default:
1342 : : break;
1343 : : }
1344 : : }
1345 : : return false;
1346 : : };
1347 : 288 : switch (pattern.get_items ().get_item_type ())
1348 : : {
1349 : 286 : case HIR::TuplePatternItems::ItemType::NO_REST:
1350 : 286 : {
1351 : 286 : auto &items
1352 : 286 : = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
1353 : 286 : has_by_ref = check_refs (items.get_patterns ());
1354 : 286 : break;
1355 : : }
1356 : 2 : case HIR::TuplePatternItems::ItemType::HAS_REST:
1357 : 2 : {
1358 : 2 : auto &items
1359 : 2 : = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
1360 : 2 : has_by_ref = check_refs (items.get_lower_patterns ())
1361 : 2 : || check_refs (items.get_upper_patterns ());
1362 : : break;
1363 : : }
1364 : : default:
1365 : : break;
1366 : : }
1367 : :
1368 : 288 : tree rhs_tuple_type = TYPE_MAIN_VARIANT (TREE_TYPE (init_expr));
1369 : 288 : tree init_stmt;
1370 : 288 : Bvariable *tmp_var
1371 : 288 : = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
1372 : : rhs_tuple_type, init_expr, has_by_ref,
1373 : 288 : pattern.get_locus (), &init_stmt);
1374 : 288 : tree access_expr = Backend::var_expression (tmp_var, pattern.get_locus ());
1375 : 288 : ctx->add_statement (init_stmt);
1376 : :
1377 : 288 : switch (pattern.get_items ().get_item_type ())
1378 : : {
1379 : 2 : case HIR::TuplePatternItems::ItemType::HAS_REST:
1380 : 2 : {
1381 : 2 : size_t tuple_idx = 0;
1382 : 2 : auto &items
1383 : 2 : = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
1384 : :
1385 : 2 : auto &items_lower = items.get_lower_patterns ();
1386 : 2 : auto &items_upper = items.get_upper_patterns ();
1387 : :
1388 : 4 : for (auto &sub : items_lower)
1389 : : {
1390 : 2 : TyTy::BaseType *ty_sub = nullptr;
1391 : 2 : HirId sub_id = sub->get_mappings ().get_hirid ();
1392 : 2 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1393 : 2 : rust_assert (ok);
1394 : :
1395 : 2 : tree sub_init
1396 : 2 : = Backend::struct_field_expression (access_expr, tuple_idx,
1397 : 2 : sub->get_locus ());
1398 : 2 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1399 : : rval_locus, ctx);
1400 : 2 : tuple_idx++;
1401 : : }
1402 : :
1403 : 2 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
1404 : 2 : tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
1405 : 2 : - items_upper.size ();
1406 : :
1407 : 4 : for (auto &sub : items_upper)
1408 : : {
1409 : 2 : TyTy::BaseType *ty_sub = nullptr;
1410 : 2 : HirId sub_id = sub->get_mappings ().get_hirid ();
1411 : 2 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1412 : 2 : rust_assert (ok);
1413 : :
1414 : 2 : tree sub_init
1415 : 2 : = Backend::struct_field_expression (access_expr, tuple_idx,
1416 : 2 : sub->get_locus ());
1417 : 2 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1418 : : rval_locus, ctx);
1419 : 2 : tuple_idx++;
1420 : : }
1421 : :
1422 : : return;
1423 : : }
1424 : 286 : case HIR::TuplePatternItems::ItemType::NO_REST:
1425 : 286 : {
1426 : 286 : size_t tuple_idx = 0;
1427 : 286 : auto &items
1428 : 286 : = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
1429 : :
1430 : 870 : for (auto &sub : items.get_patterns ())
1431 : : {
1432 : 584 : TyTy::BaseType *ty_sub = nullptr;
1433 : 584 : HirId sub_id = sub->get_mappings ().get_hirid ();
1434 : 584 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1435 : 584 : rust_assert (ok);
1436 : :
1437 : 584 : tree sub_init
1438 : 584 : = Backend::struct_field_expression (access_expr, tuple_idx,
1439 : 584 : sub->get_locus ());
1440 : 584 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1441 : : rval_locus, ctx);
1442 : 584 : tuple_idx++;
1443 : : }
1444 : :
1445 : : return;
1446 : : }
1447 : 0 : default:
1448 : 0 : {
1449 : 0 : rust_unreachable ();
1450 : : }
1451 : : }
1452 : : }
1453 : :
1454 : : } // namespace Compile
1455 : : } // namespace Rust
|