Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #include "rust-compile-pattern.h"
20 : : #include "rust-compile-expr.h"
21 : : #include "rust-compile-resolve-path.h"
22 : : #include "rust-constexpr.h"
23 : : #include "rust-compile-type.h"
24 : : #include "print-tree.h"
25 : : #include "rust-diagnostics.h"
26 : : #include "rust-hir-pattern-abstract.h"
27 : : #include "rust-hir-pattern.h"
28 : : #include "rust-system.h"
29 : : #include "rust-tyty.h"
30 : :
31 : : namespace Rust {
32 : : namespace Compile {
33 : :
34 : : void
35 : 759 : CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern)
36 : : {
37 : : // lookup the type
38 : 759 : TyTy::BaseType *lookup = nullptr;
39 : 759 : bool ok
40 : 759 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
41 : : &lookup);
42 : 759 : rust_assert (ok);
43 : :
44 : : // must be an ADT (?)
45 : 759 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
46 : 759 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
47 : :
48 : : // if this isn't an enum, always succeed
49 : 759 : if (!adt->is_enum ())
50 : : {
51 : 0 : check_expr = boolean_true_node;
52 : 0 : return;
53 : : }
54 : :
55 : : // lookup the variant
56 : 759 : HirId variant_id;
57 : 759 : ok = ctx->get_tyctx ()->lookup_variant_definition (
58 : 759 : pattern.get_mappings ().get_hirid (), &variant_id);
59 : 759 : rust_assert (ok);
60 : :
61 : 759 : TyTy::VariantDef *variant = nullptr;
62 : 759 : ok = adt->lookup_variant_by_id (variant_id, &variant);
63 : 759 : rust_assert (ok);
64 : :
65 : : // find discriminant field of scrutinee
66 : 759 : tree scrutinee_expr_qualifier_expr
67 : 759 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
68 : : pattern.get_locus ());
69 : :
70 : : // must be enum
71 : 759 : match_scrutinee_expr = scrutinee_expr_qualifier_expr;
72 : :
73 : 759 : HIR::Expr &discrim_expr = variant->get_discriminant ();
74 : 759 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
75 : :
76 : 759 : check_expr
77 : 759 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
78 : : match_scrutinee_expr, discrim_expr_node,
79 : : pattern.get_locus ());
80 : : }
81 : :
82 : : void
83 : 272 : CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern)
84 : : {
85 : : // Compile the literal
86 : 272 : auto litexpr = std::make_unique<HIR::LiteralExpr> (
87 : 544 : HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (),
88 : 544 : pattern.get_locus (), std::vector<AST::Attribute> ()));
89 : :
90 : : // Note: Floating point literals are currently accepted but will likely be
91 : : // forbidden in LiteralPatterns in a future version of Rust.
92 : : // See: https://github.com/rust-lang/rust/issues/41620
93 : : // For now, we cannot compile them anyway as CASE_LABEL_EXPR does not support
94 : : // floating point types.
95 : 272 : if (pattern.get_literal ().get_lit_type () == HIR::Literal::LitType::FLOAT)
96 : : {
97 : 0 : rust_sorry_at (pattern.get_locus (), "floating-point literal in pattern");
98 : : }
99 : :
100 : 272 : tree lit = CompileExpr::Compile (*litexpr, ctx);
101 : :
102 : 272 : check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL,
103 : : match_scrutinee_expr, lit,
104 : 272 : pattern.get_locus ());
105 : 272 : }
106 : :
107 : : static tree
108 : 42 : compile_range_pattern_bound (HIR::RangePatternBound &bound,
109 : : Analysis::NodeMapping mappings, location_t locus,
110 : : Context *ctx)
111 : : {
112 : 42 : tree result = NULL_TREE;
113 : 42 : switch (bound.get_bound_type ())
114 : : {
115 : 21 : case HIR::RangePatternBound::RangePatternBoundType::LITERAL:
116 : 21 : {
117 : 21 : auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound);
118 : :
119 : 63 : HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus,
120 : 21 : std::vector<AST::Attribute> ());
121 : :
122 : 21 : result = CompileExpr::Compile (litexpr, ctx);
123 : 21 : }
124 : 21 : break;
125 : :
126 : 21 : case HIR::RangePatternBound::RangePatternBoundType::PATH:
127 : 21 : {
128 : 21 : auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound);
129 : :
130 : 21 : result = ResolvePathRef::Compile (ref.get_path (), ctx);
131 : :
132 : : // If the path resolves to a const expression, fold it.
133 : 21 : result = fold_expr (result);
134 : : }
135 : 21 : break;
136 : :
137 : 0 : case HIR::RangePatternBound::RangePatternBoundType::QUALPATH:
138 : 0 : {
139 : 0 : auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound);
140 : :
141 : 0 : result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx);
142 : :
143 : : // If the path resolves to a const expression, fold it.
144 : 0 : result = fold_expr (result);
145 : : }
146 : : }
147 : :
148 : 42 : return result;
149 : : }
150 : :
151 : : void
152 : 21 : CompilePatternCheckExpr::visit (HIR::RangePattern &pattern)
153 : : {
154 : 21 : tree upper = compile_range_pattern_bound (pattern.get_upper_bound (),
155 : 21 : pattern.get_mappings (),
156 : 21 : pattern.get_locus (), ctx);
157 : 63 : tree lower = compile_range_pattern_bound (pattern.get_lower_bound (),
158 : 21 : pattern.get_mappings (),
159 : 21 : pattern.get_locus (), ctx);
160 : :
161 : 21 : tree check_lower
162 : 21 : = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL,
163 : : match_scrutinee_expr, lower,
164 : 21 : pattern.get_locus ());
165 : 21 : tree check_upper
166 : 21 : = Backend::comparison_expression (ComparisonOperator::LESS_OR_EQUAL,
167 : : match_scrutinee_expr, upper,
168 : 21 : pattern.get_locus ());
169 : 21 : check_expr = Backend::arithmetic_or_logical_expression (
170 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper,
171 : 21 : pattern.get_locus ());
172 : 21 : }
173 : :
174 : : void
175 : 163 : CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern)
176 : : {
177 : 163 : match_scrutinee_expr
178 : 163 : = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
179 : 163 : pattern.get_referenced_pattern ().accept_vis (*this);
180 : 163 : }
181 : :
182 : : void
183 : 43 : CompilePatternCheckExpr::visit (HIR::AltPattern &pattern)
184 : : {
185 : 43 : auto &alts = pattern.get_alts ();
186 : :
187 : 43 : check_expr = CompilePatternCheckExpr::Compile (*alts.at (0),
188 : : match_scrutinee_expr, ctx);
189 : 43 : auto end = alts.end ();
190 : 87 : for (auto i = alts.begin () + 1; i != end; i++)
191 : : {
192 : 44 : tree next_expr
193 : 44 : = CompilePatternCheckExpr::Compile (**i, match_scrutinee_expr, ctx);
194 : 44 : check_expr = Backend::arithmetic_or_logical_expression (
195 : : ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr,
196 : 44 : (*i)->get_locus ());
197 : : }
198 : 43 : }
199 : :
200 : : void
201 : 125 : CompilePatternCheckExpr::visit (HIR::StructPattern &pattern)
202 : : {
203 : : // lookup the type
204 : 125 : TyTy::BaseType *lookup = nullptr;
205 : 125 : bool ok = ctx->get_tyctx ()->lookup_type (
206 : 125 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
207 : 125 : rust_assert (ok);
208 : :
209 : : // this might be an enum
210 : 125 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
211 : 125 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
212 : :
213 : 125 : rust_assert (adt->number_of_variants () > 0);
214 : 125 : TyTy::VariantDef *variant = nullptr;
215 : 125 : tree variant_accesser_expr = nullptr;
216 : 125 : if (adt->is_enum ())
217 : : {
218 : : // lookup the variant
219 : 111 : HirId variant_id;
220 : 111 : ok = ctx->get_tyctx ()->lookup_variant_definition (
221 : 111 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
222 : 111 : rust_assert (ok);
223 : :
224 : 111 : int variant_index = 0;
225 : 111 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
226 : 111 : rust_assert (ok);
227 : :
228 : : // find expected discriminant
229 : : // // need to access qualifier the field, if we use QUAL_UNION_TYPE this
230 : : // // would be DECL_QUALIFIER i think.
231 : 111 : HIR::Expr &discrim_expr = variant->get_discriminant ();
232 : 111 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
233 : :
234 : : // find discriminant field of scrutinee
235 : 111 : tree scrutinee_expr_qualifier_expr
236 : 111 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
237 : 111 : pattern.get_path ().get_locus ());
238 : :
239 : : // access variant data
240 : 111 : tree scrutinee_union_expr
241 : 111 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
242 : 111 : pattern.get_path ().get_locus ());
243 : 111 : variant_accesser_expr
244 : 111 : = Backend::struct_field_expression (scrutinee_union_expr, variant_index,
245 : 111 : pattern.get_path ().get_locus ());
246 : :
247 : 111 : check_expr
248 : 111 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
249 : : scrutinee_expr_qualifier_expr,
250 : : discrim_expr_node,
251 : 111 : pattern.get_path ().get_locus ());
252 : :
253 : 111 : match_scrutinee_expr = scrutinee_expr_qualifier_expr;
254 : : }
255 : : else
256 : : {
257 : 14 : variant = adt->get_variants ().at (0);
258 : 14 : variant_accesser_expr = match_scrutinee_expr;
259 : 14 : check_expr = boolean_true_node;
260 : : }
261 : :
262 : 125 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
263 : 340 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
264 : : {
265 : 215 : switch (field->get_item_type ())
266 : : {
267 : 0 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
268 : 0 : {
269 : : // TODO
270 : 0 : rust_unreachable ();
271 : : }
272 : 127 : break;
273 : :
274 : 127 : case HIR::StructPatternField::ItemType::IDENT_PAT:
275 : 127 : {
276 : 127 : HIR::StructPatternFieldIdentPat &ident
277 : 127 : = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ());
278 : :
279 : 127 : size_t offs = 0;
280 : 127 : ok = variant->lookup_field (ident.get_identifier ().as_string (),
281 : : nullptr, &offs);
282 : 127 : rust_assert (ok);
283 : :
284 : 127 : tree field_expr
285 : 127 : = Backend::struct_field_expression (variant_accesser_expr, offs,
286 : : ident.get_locus ());
287 : :
288 : 127 : tree check_expr_sub
289 : 127 : = CompilePatternCheckExpr::Compile (ident.get_pattern (),
290 : : field_expr, ctx);
291 : 127 : check_expr = Backend::arithmetic_or_logical_expression (
292 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
293 : 127 : check_expr_sub, ident.get_pattern ().get_locus ());
294 : : }
295 : 127 : break;
296 : :
297 : : case HIR::StructPatternField::ItemType::IDENT:
298 : : {
299 : : // ident pattern always matches - do nothing
300 : : }
301 : : break;
302 : : }
303 : : }
304 : 125 : }
305 : :
306 : : void
307 : 704 : CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
308 : : {
309 : : // lookup the type
310 : 704 : TyTy::BaseType *lookup = nullptr;
311 : 704 : bool ok = ctx->get_tyctx ()->lookup_type (
312 : 704 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
313 : 704 : rust_assert (ok);
314 : :
315 : : // this might be an enum
316 : 704 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
317 : 704 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
318 : :
319 : 704 : int variant_index = 0;
320 : 704 : rust_assert (adt->number_of_variants () > 0);
321 : 704 : TyTy::VariantDef *variant = nullptr;
322 : 704 : if (adt->is_enum ())
323 : : {
324 : : // lookup the variant
325 : 696 : HirId variant_id;
326 : 696 : ok = ctx->get_tyctx ()->lookup_variant_definition (
327 : 696 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
328 : 696 : rust_assert (ok);
329 : :
330 : 696 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
331 : 696 : rust_assert (ok);
332 : :
333 : : // find expected discriminant
334 : 696 : HIR::Expr &discrim_expr = variant->get_discriminant ();
335 : 696 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
336 : :
337 : : // find discriminant field of scrutinee
338 : 696 : tree scrutinee_expr_qualifier_expr
339 : 696 : = Backend::struct_field_expression (match_scrutinee_expr, 0,
340 : 696 : pattern.get_path ().get_locus ());
341 : :
342 : 696 : check_expr
343 : 696 : = Backend::comparison_expression (ComparisonOperator::EQUAL,
344 : : scrutinee_expr_qualifier_expr,
345 : : discrim_expr_node,
346 : 696 : pattern.get_path ().get_locus ());
347 : : }
348 : : else
349 : : {
350 : 8 : variant = adt->get_variants ().at (0);
351 : 8 : check_expr = boolean_true_node;
352 : : }
353 : :
354 : 704 : HIR::TupleStructItems &items = pattern.get_items ();
355 : 704 : switch (items.get_item_type ())
356 : : {
357 : 0 : case HIR::TupleStructItems::RANGED:
358 : 0 : {
359 : : // TODO
360 : 0 : rust_unreachable ();
361 : : }
362 : 704 : break;
363 : :
364 : 704 : case HIR::TupleStructItems::MULTIPLE:
365 : 704 : {
366 : 704 : HIR::TupleStructItemsNoRange &items_no_range
367 : : = static_cast<HIR::TupleStructItemsNoRange &> (items);
368 : :
369 : 704 : rust_assert (items_no_range.get_patterns ().size ()
370 : : == variant->num_fields ());
371 : :
372 : 704 : if (adt->is_enum ())
373 : : {
374 : 696 : size_t tuple_field_index = 0;
375 : 1472 : for (auto &pattern : items_no_range.get_patterns ())
376 : : {
377 : : // find payload union field of scrutinee
378 : 776 : tree payload_ref
379 : 776 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
380 : 776 : pattern->get_locus ());
381 : :
382 : 776 : tree variant_ref
383 : 776 : = Backend::struct_field_expression (payload_ref,
384 : : variant_index,
385 : 776 : pattern->get_locus ());
386 : :
387 : 776 : tree field_expr
388 : 776 : = Backend::struct_field_expression (variant_ref,
389 : : tuple_field_index++,
390 : 776 : pattern->get_locus ());
391 : :
392 : 776 : tree check_expr_sub
393 : 776 : = CompilePatternCheckExpr::Compile (*pattern, field_expr,
394 : : ctx);
395 : 776 : check_expr = Backend::arithmetic_or_logical_expression (
396 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
397 : 776 : check_expr_sub, pattern->get_locus ());
398 : : }
399 : : }
400 : : else
401 : : {
402 : : // For non-enum TupleStructPatterns
403 : 8 : size_t tuple_field_index = 0;
404 : 24 : for (auto &pattern : items_no_range.get_patterns ())
405 : : {
406 : 16 : tree field_expr
407 : 16 : = Backend::struct_field_expression (match_scrutinee_expr,
408 : : tuple_field_index++,
409 : 16 : pattern->get_locus ());
410 : :
411 : 16 : tree check_expr_sub
412 : 16 : = CompilePatternCheckExpr::Compile (*pattern, field_expr,
413 : : ctx);
414 : 16 : check_expr = Backend::arithmetic_or_logical_expression (
415 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
416 : 16 : check_expr_sub, pattern->get_locus ());
417 : : }
418 : : }
419 : : break;
420 : : }
421 : : }
422 : 704 : }
423 : :
424 : : void
425 : 112 : CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
426 : : {
427 : 112 : check_expr = boolean_true_node;
428 : :
429 : 112 : switch (pattern.get_items ().get_item_type ())
430 : : {
431 : 22 : case HIR::TuplePatternItems::RANGED:
432 : 22 : {
433 : 22 : auto &items
434 : 22 : = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
435 : 22 : size_t tuple_field_index = 0;
436 : :
437 : : // lookup the type to find out number of fields
438 : 22 : TyTy::BaseType *ty = nullptr;
439 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (
440 : 22 : pattern.get_mappings ().get_hirid (), &ty);
441 : 22 : rust_assert (ok);
442 : 22 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
443 : :
444 : : // compile check expr for lower patterns
445 : 44 : for (auto &pat : items.get_lower_patterns ())
446 : : {
447 : 22 : tree field_expr
448 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
449 : : tuple_field_index++,
450 : 22 : pat->get_locus ());
451 : :
452 : 22 : tree check_expr_sub
453 : 22 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
454 : 22 : check_expr = Backend::arithmetic_or_logical_expression (
455 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
456 : 22 : check_expr_sub, pat->get_locus ());
457 : : }
458 : :
459 : : // skip the fields that are not checked
460 : 22 : tuple_field_index = static_cast<TyTy::TupleType &> (*ty).num_fields ()
461 : 22 : - items.get_upper_patterns ().size ();
462 : :
463 : : // compile check expr for upper patterns
464 : 44 : for (auto &pat : items.get_upper_patterns ())
465 : : {
466 : 22 : tree field_expr
467 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
468 : : tuple_field_index++,
469 : 22 : pat->get_locus ());
470 : :
471 : 22 : tree check_expr_sub
472 : 22 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
473 : 22 : check_expr = Backend::arithmetic_or_logical_expression (
474 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
475 : 22 : check_expr_sub, pat->get_locus ());
476 : : }
477 : : }
478 : 22 : break;
479 : :
480 : 90 : case HIR::TuplePatternItems::MULTIPLE:
481 : 90 : {
482 : 90 : auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
483 : 90 : pattern.get_items ());
484 : 90 : size_t tuple_field_index = 0;
485 : :
486 : 270 : for (auto &pat : items.get_patterns ())
487 : : {
488 : 180 : tree field_expr
489 : 180 : = Backend::struct_field_expression (match_scrutinee_expr,
490 : : tuple_field_index++,
491 : 180 : pat->get_locus ());
492 : :
493 : 180 : tree check_expr_sub
494 : 180 : = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx);
495 : 180 : check_expr = Backend::arithmetic_or_logical_expression (
496 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
497 : 180 : check_expr_sub, pat->get_locus ());
498 : : }
499 : : }
500 : : }
501 : 112 : }
502 : :
503 : : void
504 : 668 : CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern)
505 : : {
506 : 668 : if (pattern.has_subpattern ())
507 : : {
508 : 9 : check_expr = CompilePatternCheckExpr::Compile (pattern.get_subpattern (),
509 : : match_scrutinee_expr, ctx);
510 : : }
511 : : else
512 : : {
513 : 659 : check_expr = boolean_true_node;
514 : : }
515 : 668 : }
516 : :
517 : : void
518 : 31 : CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
519 : : {
520 : 31 : check_expr = boolean_true_node;
521 : :
522 : : // lookup the type
523 : 31 : TyTy::BaseType *lookup = nullptr;
524 : 31 : bool ok
525 : 31 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
526 : : &lookup);
527 : 31 : rust_assert (ok);
528 : :
529 : : // pattern must either be ArrayType or SliceType, should be already confirmed
530 : : // by type checking
531 : 31 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
532 : : || lookup->get_kind () == TyTy::TypeKind::SLICE
533 : : || lookup->get_kind () == TyTy::REF);
534 : :
535 : 31 : size_t array_element_index = 0;
536 : 31 : switch (lookup->get_kind ())
537 : : {
538 : 15 : case TyTy::TypeKind::ARRAY:
539 : 45 : for (auto &pattern_member : pattern.get_items ())
540 : : {
541 : 30 : tree array_index_tree
542 : 30 : = Backend::size_constant_expression (array_element_index++);
543 : 30 : tree element_expr
544 : 30 : = Backend::array_index_expression (match_scrutinee_expr,
545 : : array_index_tree,
546 : 30 : pattern.get_locus ());
547 : 30 : tree check_expr_sub
548 : 30 : = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
549 : : ctx);
550 : 30 : check_expr = Backend::arithmetic_or_logical_expression (
551 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
552 : 30 : check_expr_sub, pattern.get_locus ());
553 : : }
554 : : break;
555 : 0 : case TyTy::TypeKind::SLICE:
556 : 0 : rust_sorry_at (
557 : : pattern.get_locus (),
558 : : "SlicePattern matching against non-ref slices are not yet supported");
559 : 0 : break;
560 : 16 : case TyTy::TypeKind::REF:
561 : 16 : {
562 : 16 : rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
563 : 16 : tree size_field
564 : 16 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
565 : 16 : pattern.get_locus ());
566 : :
567 : : // First compare the size
568 : 16 : check_expr = Backend::comparison_expression (
569 : : ComparisonOperator::EQUAL, size_field,
570 : 16 : build_int_cst (size_type_node, pattern.get_items ().size ()),
571 : 16 : pattern.get_locus ());
572 : :
573 : : // Then compare each element in the slice pattern
574 : 47 : for (auto &pattern_member : pattern.get_items ())
575 : : {
576 : 31 : tree slice_index_tree
577 : 31 : = Backend::size_constant_expression (array_element_index++);
578 : 31 : tree element_expr
579 : 31 : = Backend::slice_index_expression (match_scrutinee_expr,
580 : : slice_index_tree,
581 : 31 : pattern.get_locus ());
582 : 31 : tree check_expr_sub
583 : 31 : = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
584 : : ctx);
585 : 31 : check_expr = Backend::arithmetic_or_logical_expression (
586 : : ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
587 : 31 : check_expr_sub, pattern.get_locus ());
588 : : }
589 : : }
590 : : break;
591 : 0 : default:
592 : 0 : rust_unreachable ();
593 : : }
594 : 31 : }
595 : :
596 : : // setup the bindings
597 : :
598 : : void
599 : 690 : CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
600 : : {
601 : : // lookup the type
602 : 690 : TyTy::BaseType *lookup = nullptr;
603 : 690 : bool ok = ctx->get_tyctx ()->lookup_type (
604 : 690 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
605 : 690 : rust_assert (ok);
606 : :
607 : : // this must be an enum
608 : 690 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
609 : 690 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
610 : 690 : rust_assert (adt->number_of_variants () > 0);
611 : :
612 : 690 : int variant_index = 0;
613 : 690 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
614 : 690 : if (adt->is_enum ())
615 : : {
616 : 668 : HirId variant_id = UNKNOWN_HIRID;
617 : 668 : bool ok = ctx->get_tyctx ()->lookup_variant_definition (
618 : 668 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
619 : 668 : rust_assert (ok);
620 : :
621 : 668 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
622 : 668 : rust_assert (ok);
623 : : }
624 : :
625 : 690 : rust_assert (variant->get_variant_type ()
626 : : == TyTy::VariantDef::VariantType::TUPLE);
627 : :
628 : 690 : HIR::TupleStructItems &items = pattern.get_items ();
629 : 690 : switch (items.get_item_type ())
630 : : {
631 : 0 : case HIR::TupleStructItems::RANGED:
632 : 0 : {
633 : : // TODO
634 : 0 : rust_unreachable ();
635 : : }
636 : 690 : break;
637 : :
638 : 690 : case HIR::TupleStructItems::MULTIPLE:
639 : 690 : {
640 : 690 : HIR::TupleStructItemsNoRange &items_no_range
641 : : = static_cast<HIR::TupleStructItemsNoRange &> (items);
642 : :
643 : 690 : rust_assert (items_no_range.get_patterns ().size ()
644 : : == variant->num_fields ());
645 : :
646 : 690 : if (adt->is_enum ())
647 : : {
648 : 668 : size_t tuple_field_index = 0;
649 : 1416 : for (auto &pattern : items_no_range.get_patterns ())
650 : : {
651 : 748 : tree payload_accessor_union
652 : 748 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
653 : 748 : pattern->get_locus ());
654 : :
655 : 748 : tree variant_accessor
656 : 748 : = Backend::struct_field_expression (payload_accessor_union,
657 : : variant_index,
658 : 748 : pattern->get_locus ());
659 : :
660 : 748 : tree binding
661 : 748 : = Backend::struct_field_expression (variant_accessor,
662 : : tuple_field_index++,
663 : 748 : pattern->get_locus ());
664 : :
665 : 748 : CompilePatternBindings::Compile (*pattern, binding, ctx);
666 : : }
667 : : }
668 : : else
669 : : {
670 : 22 : size_t tuple_field_index = 0;
671 : 59 : for (auto &pattern : items_no_range.get_patterns ())
672 : : {
673 : 37 : tree variant_accessor = match_scrutinee_expr;
674 : :
675 : 37 : tree binding
676 : 37 : = Backend::struct_field_expression (variant_accessor,
677 : : tuple_field_index++,
678 : 37 : pattern->get_locus ());
679 : :
680 : 37 : CompilePatternBindings::Compile (*pattern, binding, ctx);
681 : : }
682 : : }
683 : : }
684 : : break;
685 : : }
686 : 690 : }
687 : :
688 : : tree
689 : 215 : CompilePatternBindings::make_struct_access (TyTy::ADTType *adt,
690 : : TyTy::VariantDef *variant,
691 : : const Identifier &ident,
692 : : int variant_index)
693 : : {
694 : 215 : size_t offs = 0;
695 : 215 : auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs);
696 : 215 : rust_assert (ok);
697 : :
698 : 215 : if (adt->is_enum ())
699 : : {
700 : 187 : tree payload_accessor_union
701 : 187 : = Backend::struct_field_expression (match_scrutinee_expr, 1,
702 : : ident.get_locus ());
703 : :
704 : 187 : tree variant_accessor
705 : 187 : = Backend::struct_field_expression (payload_accessor_union,
706 : : variant_index, ident.get_locus ());
707 : :
708 : 187 : return Backend::struct_field_expression (variant_accessor, offs,
709 : 187 : ident.get_locus ());
710 : : }
711 : : else
712 : : {
713 : 28 : tree variant_accessor = match_scrutinee_expr;
714 : :
715 : 28 : return Backend::struct_field_expression (variant_accessor, offs,
716 : 28 : ident.get_locus ());
717 : : }
718 : : }
719 : :
720 : : void
721 : 88 : CompilePatternBindings::handle_struct_pattern_ident (
722 : : HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
723 : : int variant_index)
724 : : {
725 : 88 : HIR::StructPatternFieldIdent &ident
726 : : = static_cast<HIR::StructPatternFieldIdent &> (pat);
727 : :
728 : 88 : auto identifier = ident.get_identifier ();
729 : 88 : tree binding = make_struct_access (adt, variant, identifier, variant_index);
730 : :
731 : 88 : ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding);
732 : 88 : }
733 : :
734 : : void
735 : 127 : CompilePatternBindings::handle_struct_pattern_ident_pat (
736 : : HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant,
737 : : int variant_index)
738 : : {
739 : 127 : auto &pattern = static_cast<HIR::StructPatternFieldIdentPat &> (pat);
740 : :
741 : 127 : tree binding = make_struct_access (adt, variant, pattern.get_identifier (),
742 : : variant_index);
743 : 127 : CompilePatternBindings::Compile (pattern.get_pattern (), binding, ctx);
744 : 127 : }
745 : :
746 : : void
747 : 0 : CompilePatternBindings::handle_struct_pattern_tuple_pat (
748 : : HIR::StructPatternField &pat)
749 : : {
750 : 0 : rust_unreachable ();
751 : : }
752 : :
753 : : void
754 : 125 : CompilePatternBindings::visit (HIR::StructPattern &pattern)
755 : : {
756 : : // lookup the type
757 : 125 : TyTy::BaseType *lookup = nullptr;
758 : 125 : bool ok = ctx->get_tyctx ()->lookup_type (
759 : 125 : pattern.get_path ().get_mappings ().get_hirid (), &lookup);
760 : 125 : rust_assert (ok);
761 : :
762 : : // this must be an enum
763 : 125 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
764 : 125 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
765 : 125 : rust_assert (adt->number_of_variants () > 0);
766 : :
767 : 125 : int variant_index = 0;
768 : 125 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
769 : 125 : if (adt->is_enum ())
770 : : {
771 : 111 : HirId variant_id = UNKNOWN_HIRID;
772 : 111 : bool ok = ctx->get_tyctx ()->lookup_variant_definition (
773 : 111 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
774 : 111 : rust_assert (ok);
775 : :
776 : 111 : ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
777 : 111 : rust_assert (ok);
778 : : }
779 : :
780 : 125 : rust_assert (variant->get_variant_type ()
781 : : == TyTy::VariantDef::VariantType::STRUCT);
782 : :
783 : 125 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
784 : 340 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
785 : : {
786 : 215 : switch (field->get_item_type ())
787 : : {
788 : 0 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
789 : 0 : handle_struct_pattern_tuple_pat (*field);
790 : 0 : break;
791 : 127 : case HIR::StructPatternField::ItemType::IDENT_PAT:
792 : 127 : handle_struct_pattern_ident_pat (*field, adt, variant, variant_index);
793 : 127 : break;
794 : 88 : case HIR::StructPatternField::ItemType::IDENT:
795 : 88 : handle_struct_pattern_ident (*field, adt, variant, variant_index);
796 : 88 : break;
797 : : }
798 : : }
799 : 125 : }
800 : :
801 : : void
802 : 193 : CompilePatternBindings::visit (HIR::ReferencePattern &pattern)
803 : : {
804 : 193 : tree derefed
805 : 193 : = indirect_expression (match_scrutinee_expr, pattern.get_locus ());
806 : :
807 : 193 : CompilePatternBindings::Compile (pattern.get_referenced_pattern (), derefed,
808 : : ctx);
809 : 193 : }
810 : :
811 : : void
812 : 750 : CompilePatternBindings::visit (HIR::IdentifierPattern &pattern)
813 : : {
814 : 750 : if (pattern.has_subpattern ())
815 : : {
816 : 9 : CompilePatternBindings::Compile (pattern.get_subpattern (),
817 : : match_scrutinee_expr, ctx);
818 : : }
819 : :
820 : 750 : if (!pattern.get_is_ref ())
821 : : {
822 : 749 : ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (),
823 : : match_scrutinee_expr);
824 : 749 : return;
825 : : }
826 : :
827 : 1 : tree ref = address_expression (match_scrutinee_expr,
828 : 1 : EXPR_LOCATION (match_scrutinee_expr));
829 : 1 : ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), ref);
830 : : }
831 : :
832 : : void
833 : 113 : CompilePatternBindings::visit (HIR::TuplePattern &pattern)
834 : : {
835 : 113 : rust_assert (pattern.has_tuple_pattern_items ());
836 : :
837 : : // lookup the type
838 : 113 : TyTy::BaseType *ty = nullptr;
839 : 113 : bool ok
840 : 113 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
841 : : &ty);
842 : 113 : rust_assert (ok);
843 : :
844 : 113 : switch (pattern.get_items ().get_item_type ())
845 : : {
846 : 22 : case HIR::TuplePatternItems::ItemType::RANGED:
847 : 22 : {
848 : 22 : size_t tuple_idx = 0;
849 : 22 : auto &items
850 : 22 : = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
851 : :
852 : 22 : auto &items_lower = items.get_lower_patterns ();
853 : 22 : auto &items_upper = items.get_upper_patterns ();
854 : :
855 : 44 : for (auto &sub : items_lower)
856 : : {
857 : 22 : TyTy::BaseType *ty_sub = nullptr;
858 : 22 : HirId sub_id = sub->get_mappings ().get_hirid ();
859 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
860 : 22 : rust_assert (ok);
861 : :
862 : 22 : tree sub_init
863 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
864 : 22 : tuple_idx, sub->get_locus ());
865 : :
866 : 22 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
867 : 22 : tuple_idx++;
868 : : }
869 : :
870 : 22 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
871 : 22 : tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
872 : 22 : - items_upper.size ();
873 : :
874 : 44 : for (auto &sub : items_upper)
875 : : {
876 : 22 : TyTy::BaseType *ty_sub = nullptr;
877 : 22 : HirId sub_id = sub->get_mappings ().get_hirid ();
878 : 22 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
879 : 22 : rust_assert (ok);
880 : :
881 : 22 : tree sub_init
882 : 22 : = Backend::struct_field_expression (match_scrutinee_expr,
883 : 22 : tuple_idx, sub->get_locus ());
884 : 22 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
885 : 22 : tuple_idx++;
886 : : }
887 : :
888 : : return;
889 : : }
890 : 91 : case HIR::TuplePatternItems::ItemType::MULTIPLE:
891 : 91 : {
892 : 91 : size_t tuple_idx = 0;
893 : 91 : auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
894 : 91 : pattern.get_items ());
895 : :
896 : 273 : for (auto &sub : items.get_patterns ())
897 : : {
898 : 182 : TyTy::BaseType *ty_sub = nullptr;
899 : 182 : HirId sub_id = sub->get_mappings ().get_hirid ();
900 : 182 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
901 : 182 : rust_assert (ok);
902 : :
903 : 182 : tree sub_init
904 : 182 : = Backend::struct_field_expression (match_scrutinee_expr,
905 : 182 : tuple_idx, sub->get_locus ());
906 : 182 : CompilePatternBindings::Compile (*sub.get (), sub_init, ctx);
907 : 182 : tuple_idx++;
908 : : }
909 : :
910 : : return;
911 : : }
912 : 0 : default:
913 : 0 : {
914 : 0 : rust_unreachable ();
915 : : }
916 : : }
917 : : }
918 : :
919 : : void
920 : 31 : CompilePatternBindings::visit (HIR::SlicePattern &pattern)
921 : : {
922 : : // lookup the type
923 : 31 : TyTy::BaseType *lookup = nullptr;
924 : 31 : bool ok
925 : 31 : = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
926 : : &lookup);
927 : 31 : rust_assert (ok);
928 : :
929 : 31 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY
930 : : || lookup->get_kind () == TyTy::TypeKind::SLICE
931 : : || lookup->get_kind () == TyTy::REF);
932 : :
933 : 31 : size_t array_element_index = 0;
934 : 31 : switch (lookup->get_kind ())
935 : : {
936 : 15 : case TyTy::TypeKind::ARRAY:
937 : 45 : for (auto &pattern_member : pattern.get_items ())
938 : : {
939 : 30 : tree array_index_tree
940 : 30 : = Backend::size_constant_expression (array_element_index++);
941 : 30 : tree element_expr
942 : 30 : = Backend::array_index_expression (match_scrutinee_expr,
943 : : array_index_tree,
944 : 30 : pattern.get_locus ());
945 : 30 : CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
946 : : }
947 : : break;
948 : 0 : case TyTy::TypeKind::SLICE:
949 : 0 : rust_sorry_at (
950 : : pattern.get_locus (),
951 : : "SlicePattern matching against non-ref slices are not yet supported");
952 : 0 : break;
953 : 16 : case TyTy::TypeKind::REF:
954 : 16 : {
955 : 47 : for (auto &pattern_member : pattern.get_items ())
956 : : {
957 : 31 : tree slice_index_tree
958 : 31 : = Backend::size_constant_expression (array_element_index++);
959 : 31 : tree element_expr
960 : 31 : = Backend::slice_index_expression (match_scrutinee_expr,
961 : : slice_index_tree,
962 : 31 : pattern.get_locus ());
963 : 31 : CompilePatternBindings::Compile (*pattern_member, element_expr,
964 : : ctx);
965 : : }
966 : : break;
967 : : }
968 : 0 : default:
969 : 0 : rust_unreachable ();
970 : : }
971 : 31 : }
972 : :
973 : : //
974 : :
975 : : void
976 : 10865 : CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
977 : : {
978 : 10865 : Bvariable *var = nullptr;
979 : 10865 : rust_assert (
980 : : ctx->lookup_var_decl (pattern.get_mappings ().get_hirid (), &var));
981 : :
982 : 10865 : auto fnctx = ctx->peek_fn ();
983 : 10865 : if (ty->is_unit ())
984 : : {
985 : 227 : ctx->add_statement (init_expr);
986 : :
987 : 227 : auto unit_type_init_expr = unit_expression (rval_locus);
988 : 227 : auto s = Backend::init_statement (fnctx.fndecl, var, unit_type_init_expr);
989 : 227 : ctx->add_statement (s);
990 : : }
991 : : else
992 : : {
993 : 10638 : auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
994 : 10638 : ctx->add_statement (s);
995 : : }
996 : 10865 : }
997 : :
998 : : void
999 : 188 : CompilePatternLet::visit (HIR::WildcardPattern &pattern)
1000 : : {
1001 : 188 : tree init_stmt = NULL;
1002 : 188 : tree stmt_type = TyTyResolveCompile::compile (ctx, ty);
1003 : :
1004 : 188 : Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, stmt_type,
1005 : 188 : init_expr, false, pattern.get_locus (),
1006 : : &init_stmt);
1007 : :
1008 : 188 : ctx->add_statement (init_stmt);
1009 : 188 : }
1010 : :
1011 : : void
1012 : 278 : CompilePatternLet::visit (HIR::TuplePattern &pattern)
1013 : : {
1014 : 278 : rust_assert (pattern.has_tuple_pattern_items ());
1015 : :
1016 : 278 : tree tuple_type = TyTyResolveCompile::compile (ctx, ty);
1017 : 278 : tree init_stmt;
1018 : 278 : Bvariable *tmp_var
1019 : 278 : = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
1020 : : tuple_type, init_expr, false,
1021 : 278 : pattern.get_locus (), &init_stmt);
1022 : 278 : tree access_expr = Backend::var_expression (tmp_var, pattern.get_locus ());
1023 : 278 : ctx->add_statement (init_stmt);
1024 : :
1025 : 278 : switch (pattern.get_items ().get_item_type ())
1026 : : {
1027 : 0 : case HIR::TuplePatternItems::ItemType::RANGED:
1028 : 0 : {
1029 : 0 : size_t tuple_idx = 0;
1030 : 0 : auto &items
1031 : 0 : = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
1032 : :
1033 : 0 : auto &items_lower = items.get_lower_patterns ();
1034 : 0 : auto &items_upper = items.get_upper_patterns ();
1035 : :
1036 : 0 : for (auto &sub : items_lower)
1037 : : {
1038 : 0 : TyTy::BaseType *ty_sub = nullptr;
1039 : 0 : HirId sub_id = sub->get_mappings ().get_hirid ();
1040 : 0 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1041 : 0 : rust_assert (ok);
1042 : :
1043 : 0 : tree sub_init
1044 : 0 : = Backend::struct_field_expression (access_expr, tuple_idx,
1045 : 0 : sub->get_locus ());
1046 : 0 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1047 : : rval_locus, ctx);
1048 : 0 : tuple_idx++;
1049 : : }
1050 : :
1051 : 0 : rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE);
1052 : 0 : tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields ()
1053 : 0 : - items_upper.size ();
1054 : :
1055 : 0 : for (auto &sub : items_upper)
1056 : : {
1057 : 0 : TyTy::BaseType *ty_sub = nullptr;
1058 : 0 : HirId sub_id = sub->get_mappings ().get_hirid ();
1059 : 0 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1060 : 0 : rust_assert (ok);
1061 : :
1062 : 0 : tree sub_init
1063 : 0 : = Backend::struct_field_expression (access_expr, tuple_idx,
1064 : 0 : sub->get_locus ());
1065 : 0 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1066 : : rval_locus, ctx);
1067 : 0 : tuple_idx++;
1068 : : }
1069 : :
1070 : : return;
1071 : : }
1072 : 278 : case HIR::TuplePatternItems::ItemType::MULTIPLE:
1073 : 278 : {
1074 : 278 : size_t tuple_idx = 0;
1075 : 278 : auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
1076 : 278 : pattern.get_items ());
1077 : :
1078 : 839 : for (auto &sub : items.get_patterns ())
1079 : : {
1080 : 561 : TyTy::BaseType *ty_sub = nullptr;
1081 : 561 : HirId sub_id = sub->get_mappings ().get_hirid ();
1082 : 561 : bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub);
1083 : 561 : rust_assert (ok);
1084 : :
1085 : 561 : tree sub_init
1086 : 561 : = Backend::struct_field_expression (access_expr, tuple_idx,
1087 : 561 : sub->get_locus ());
1088 : 561 : CompilePatternLet::Compile (sub.get (), sub_init, ty_sub,
1089 : : rval_locus, ctx);
1090 : 561 : tuple_idx++;
1091 : : }
1092 : :
1093 : : return;
1094 : : }
1095 : 0 : default:
1096 : 0 : {
1097 : 0 : rust_unreachable ();
1098 : : }
1099 : : }
1100 : : }
1101 : :
1102 : : } // namespace Compile
1103 : : } // namespace Rust
|