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