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