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