1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
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"
29 CompilePatternCheckExpr::visit (HIR::PathInExpression
&pattern
)
32 TyTy::BaseType
*lookup
= nullptr;
34 = ctx
->get_tyctx ()->lookup_type (pattern
.get_mappings ().get_hirid (),
38 // this must be an enum
40 rust_assert (lookup
->get_kind () == TyTy::TypeKind::ADT
);
41 TyTy::ADTType
*adt
= static_cast<TyTy::ADTType
*> (lookup
);
42 rust_assert (adt
->is_enum ());
46 ok
= ctx
->get_tyctx ()->lookup_variant_definition (
47 pattern
.get_mappings ().get_hirid (), &variant_id
);
50 TyTy::VariantDef
*variant
= nullptr;
51 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
);
54 // find discriminant field of scrutinee
55 tree scrutinee_record_expr
56 = Backend::struct_field_expression (match_scrutinee_expr
, 0,
57 pattern
.get_locus ());
58 tree scrutinee_expr_qualifier_expr
59 = Backend::struct_field_expression (scrutinee_record_expr
, 0,
60 pattern
.get_locus ());
63 match_scrutinee_expr
= scrutinee_expr_qualifier_expr
;
65 HIR::Expr
*discrim_expr
= variant
->get_discriminant ();
66 tree discrim_expr_node
= CompileExpr::Compile (discrim_expr
, ctx
);
69 = Backend::comparison_expression (ComparisonOperator::EQUAL
,
70 match_scrutinee_expr
, discrim_expr_node
,
71 pattern
.get_locus ());
75 CompilePatternCheckExpr::visit (HIR::LiteralPattern
&pattern
)
77 // Compile the literal
78 HIR::LiteralExpr
*litexpr
79 = new HIR::LiteralExpr (pattern
.get_mappings (), pattern
.get_literal (),
81 std::vector
<AST::Attribute
> ());
83 // Note: Floating point literals are currently accepted but will likely be
84 // forbidden in LiteralPatterns in a future version of Rust.
85 // See: https://github.com/rust-lang/rust/issues/41620
86 // For now, we cannot compile them anyway as CASE_LABEL_EXPR does not support
87 // floating point types.
88 if (pattern
.get_literal ().get_lit_type () == HIR::Literal::LitType::FLOAT
)
90 rust_sorry_at (pattern
.get_locus (), "floating-point literal in pattern");
93 tree lit
= CompileExpr::Compile (litexpr
, ctx
);
95 check_expr
= Backend::comparison_expression (ComparisonOperator::EQUAL
,
96 match_scrutinee_expr
, lit
,
97 pattern
.get_locus ());
101 compile_range_pattern_bound (HIR::RangePatternBound
*bound
,
102 Analysis::NodeMapping mappings
, location_t locus
,
105 tree result
= NULL_TREE
;
106 switch (bound
->get_bound_type ())
108 case HIR::RangePatternBound::RangePatternBoundType::LITERAL
: {
109 HIR::RangePatternBoundLiteral
&ref
110 = *static_cast<HIR::RangePatternBoundLiteral
*> (bound
);
112 HIR::LiteralExpr
*litexpr
113 = new HIR::LiteralExpr (mappings
, ref
.get_literal (), locus
,
114 std::vector
<AST::Attribute
> ());
116 result
= CompileExpr::Compile (litexpr
, ctx
);
120 case HIR::RangePatternBound::RangePatternBoundType::PATH
: {
121 HIR::RangePatternBoundPath
&ref
122 = *static_cast<HIR::RangePatternBoundPath
*> (bound
);
124 result
= ResolvePathRef::Compile (ref
.get_path (), ctx
);
126 // If the path resolves to a const expression, fold it.
127 result
= fold_expr (result
);
131 case HIR::RangePatternBound::RangePatternBoundType::QUALPATH
: {
132 HIR::RangePatternBoundQualPath
&ref
133 = *static_cast<HIR::RangePatternBoundQualPath
*> (bound
);
135 result
= ResolvePathRef::Compile (ref
.get_qualified_path (), ctx
);
137 // If the path resolves to a const expression, fold it.
138 result
= fold_expr (result
);
146 CompilePatternCheckExpr::visit (HIR::RangePattern
&pattern
)
148 tree upper
= compile_range_pattern_bound (pattern
.get_upper_bound ().get (),
149 pattern
.get_mappings (),
150 pattern
.get_locus (), ctx
);
151 tree lower
= compile_range_pattern_bound (pattern
.get_lower_bound ().get (),
152 pattern
.get_mappings (),
153 pattern
.get_locus (), ctx
);
156 = Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL
,
157 match_scrutinee_expr
, lower
,
158 pattern
.get_locus ());
160 = Backend::comparison_expression (ComparisonOperator::LESS_OR_EQUAL
,
161 match_scrutinee_expr
, upper
,
162 pattern
.get_locus ());
163 check_expr
= Backend::arithmetic_or_logical_expression (
164 ArithmeticOrLogicalOperator::BITWISE_AND
, check_lower
, check_upper
,
165 pattern
.get_locus ());
169 CompilePatternCheckExpr::visit (HIR::ReferencePattern
&pattern
)
172 = indirect_expression (match_scrutinee_expr
, pattern
.get_locus ());
173 pattern
.get_referenced_pattern ()->accept_vis (*this);
177 CompilePatternCheckExpr::visit (HIR::AltPattern
&pattern
)
179 auto &alts
= pattern
.get_alts ();
181 check_expr
= CompilePatternCheckExpr::Compile (alts
.at (0).get (),
182 match_scrutinee_expr
, ctx
);
183 auto end
= alts
.end ();
184 for (auto i
= alts
.begin () + 1; i
!= end
; i
++)
187 = CompilePatternCheckExpr::Compile (i
->get (), match_scrutinee_expr
,
189 check_expr
= Backend::arithmetic_or_logical_expression (
190 ArithmeticOrLogicalOperator::BITWISE_OR
, check_expr
, next_expr
,
196 CompilePatternCheckExpr::visit (HIR::StructPattern
&pattern
)
199 TyTy::BaseType
*lookup
= nullptr;
200 bool ok
= ctx
->get_tyctx ()->lookup_type (
201 pattern
.get_path ().get_mappings ().get_hirid (), &lookup
);
204 // this might be an enum
205 rust_assert (lookup
->get_kind () == TyTy::TypeKind::ADT
);
206 TyTy::ADTType
*adt
= static_cast<TyTy::ADTType
*> (lookup
);
208 rust_assert (adt
->number_of_variants () > 0);
209 TyTy::VariantDef
*variant
= nullptr;
212 // lookup the variant
214 ok
= ctx
->get_tyctx ()->lookup_variant_definition (
215 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
218 int variant_index
= 0;
219 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
, &variant_index
);
222 // find expected discriminant
223 // // need to access qualifier the field, if we use QUAL_UNION_TYPE this
224 // // would be DECL_QUALIFIER i think. For now this will just access the
225 // // first record field and its respective qualifier because it will
226 // // always be set because this is all a big special union
227 HIR::Expr
*discrim_expr
= variant
->get_discriminant ();
228 tree discrim_expr_node
= CompileExpr::Compile (discrim_expr
, ctx
);
230 // find discriminant field of scrutinee
231 tree scrutinee_record_expr
232 = Backend::struct_field_expression (match_scrutinee_expr
, variant_index
,
233 pattern
.get_path ().get_locus ());
234 tree scrutinee_expr_qualifier_expr
235 = Backend::struct_field_expression (scrutinee_record_expr
, 0,
236 pattern
.get_path ().get_locus ());
239 = Backend::comparison_expression (ComparisonOperator::EQUAL
,
240 scrutinee_expr_qualifier_expr
,
242 pattern
.get_path ().get_locus ());
244 match_scrutinee_expr
= scrutinee_record_expr
;
248 variant
= adt
->get_variants ().at (0);
249 check_expr
= boolean_true_node
;
252 auto &struct_pattern_elems
= pattern
.get_struct_pattern_elems ();
253 for (auto &field
: struct_pattern_elems
.get_struct_pattern_fields ())
255 switch (field
->get_item_type ())
257 case HIR::StructPatternField::ItemType::TUPLE_PAT
: {
263 case HIR::StructPatternField::ItemType::IDENT_PAT
: {
264 HIR::StructPatternFieldIdentPat
&ident
265 = static_cast<HIR::StructPatternFieldIdentPat
&> (*field
.get ());
268 ok
= variant
->lookup_field (ident
.get_identifier ().as_string (),
272 // we may be offsetting by + 1 here since the first field in the
273 // record is always the discriminator
274 offs
+= adt
->is_enum ();
276 = Backend::struct_field_expression (match_scrutinee_expr
, offs
,
280 = CompilePatternCheckExpr::Compile (ident
.get_pattern ().get (),
282 check_expr
= Backend::arithmetic_or_logical_expression (
283 ArithmeticOrLogicalOperator::BITWISE_AND
, check_expr
,
284 check_expr_sub
, ident
.get_pattern ()->get_locus ());
288 case HIR::StructPatternField::ItemType::IDENT
: {
289 // ident pattern always matches - do nothing
297 CompilePatternCheckExpr::visit (HIR::TupleStructPattern
&pattern
)
299 size_t tuple_field_index
;
302 TyTy::BaseType
*lookup
= nullptr;
303 bool ok
= ctx
->get_tyctx ()->lookup_type (
304 pattern
.get_path ().get_mappings ().get_hirid (), &lookup
);
307 // this might be an enum
308 rust_assert (lookup
->get_kind () == TyTy::TypeKind::ADT
);
309 TyTy::ADTType
*adt
= static_cast<TyTy::ADTType
*> (lookup
);
311 rust_assert (adt
->number_of_variants () > 0);
312 TyTy::VariantDef
*variant
= nullptr;
315 // lookup the variant
317 ok
= ctx
->get_tyctx ()->lookup_variant_definition (
318 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
321 int variant_index
= 0;
322 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
, &variant_index
);
325 // find expected discriminant
326 HIR::Expr
*discrim_expr
= variant
->get_discriminant ();
327 tree discrim_expr_node
= CompileExpr::Compile (discrim_expr
, ctx
);
329 // find discriminant field of scrutinee
330 tree scrutinee_record_expr
331 = Backend::struct_field_expression (match_scrutinee_expr
, variant_index
,
332 pattern
.get_path ().get_locus ());
333 tree scrutinee_expr_qualifier_expr
334 = Backend::struct_field_expression (scrutinee_record_expr
, 0,
335 pattern
.get_path ().get_locus ());
338 = Backend::comparison_expression (ComparisonOperator::EQUAL
,
339 scrutinee_expr_qualifier_expr
,
341 pattern
.get_path ().get_locus ());
343 match_scrutinee_expr
= scrutinee_record_expr
;
344 // we are offsetting by + 1 here since the first field in the record
345 // is always the discriminator
346 tuple_field_index
= 1;
350 variant
= adt
->get_variants ().at (0);
351 check_expr
= boolean_true_node
;
352 tuple_field_index
= 0;
355 std::unique_ptr
<HIR::TupleStructItems
> &items
= pattern
.get_items ();
356 switch (items
->get_item_type ())
358 case HIR::TupleStructItems::RANGED
: {
364 case HIR::TupleStructItems::MULTIPLE
: {
365 HIR::TupleStructItemsNoRange
&items_no_range
366 = static_cast<HIR::TupleStructItemsNoRange
&> (*items
.get ());
368 rust_assert (items_no_range
.get_patterns ().size ()
369 == variant
->num_fields ());
371 for (auto &pattern
: items_no_range
.get_patterns ())
374 = Backend::struct_field_expression (match_scrutinee_expr
,
376 pattern
->get_locus ());
379 = CompilePatternCheckExpr::Compile (pattern
.get (), field_expr
,
381 check_expr
= Backend::arithmetic_or_logical_expression (
382 ArithmeticOrLogicalOperator::BITWISE_AND
, check_expr
,
383 check_expr_sub
, pattern
->get_locus ());
391 CompilePatternCheckExpr::visit (HIR::TuplePattern
&pattern
)
393 check_expr
= boolean_true_node
;
395 switch (pattern
.get_items ()->get_item_type ())
397 case HIR::TuplePatternItems::RANGED
: {
403 case HIR::TuplePatternItems::MULTIPLE
: {
404 auto &items
= static_cast<HIR::TuplePatternItemsMultiple
&> (
405 *pattern
.get_items ());
406 size_t tuple_field_index
= 0;
408 for (auto &pat
: items
.get_patterns ())
411 = Backend::struct_field_expression (match_scrutinee_expr
,
416 = CompilePatternCheckExpr::Compile (pat
.get (), field_expr
, ctx
);
417 check_expr
= Backend::arithmetic_or_logical_expression (
418 ArithmeticOrLogicalOperator::BITWISE_AND
, check_expr
,
419 check_expr_sub
, pat
->get_locus ());
425 // setup the bindings
428 CompilePatternBindings::visit (HIR::TupleStructPattern
&pattern
)
431 TyTy::BaseType
*lookup
= nullptr;
432 bool ok
= ctx
->get_tyctx ()->lookup_type (
433 pattern
.get_path ().get_mappings ().get_hirid (), &lookup
);
436 // this must be an enum
437 rust_assert (lookup
->get_kind () == TyTy::TypeKind::ADT
);
438 TyTy::ADTType
*adt
= static_cast<TyTy::ADTType
*> (lookup
);
439 rust_assert (adt
->number_of_variants () > 0);
441 int variant_index
= 0;
442 TyTy::VariantDef
*variant
= adt
->get_variants ().at (0);
445 HirId variant_id
= UNKNOWN_HIRID
;
446 bool ok
= ctx
->get_tyctx ()->lookup_variant_definition (
447 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
450 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
, &variant_index
);
454 rust_assert (variant
->get_variant_type ()
455 == TyTy::VariantDef::VariantType::TUPLE
);
457 std::unique_ptr
<HIR::TupleStructItems
> &items
= pattern
.get_items ();
458 switch (items
->get_item_type ())
460 case HIR::TupleStructItems::RANGED
: {
466 case HIR::TupleStructItems::MULTIPLE
: {
467 HIR::TupleStructItemsNoRange
&items_no_range
468 = static_cast<HIR::TupleStructItemsNoRange
&> (*items
.get ());
470 rust_assert (items_no_range
.get_patterns ().size ()
471 == variant
->num_fields ());
475 // we are offsetting by + 1 here since the first field in the record
476 // is always the discriminator
477 size_t tuple_field_index
= 1;
478 for (auto &pattern
: items_no_range
.get_patterns ())
480 tree variant_accessor
481 = Backend::struct_field_expression (match_scrutinee_expr
,
483 pattern
->get_locus ());
486 = Backend::struct_field_expression (variant_accessor
,
488 pattern
->get_locus ());
490 ctx
->insert_pattern_binding (
491 pattern
->get_mappings ().get_hirid (), binding
);
496 size_t tuple_field_index
= 0;
497 for (auto &pattern
: items_no_range
.get_patterns ())
499 tree variant_accessor
= match_scrutinee_expr
;
502 = Backend::struct_field_expression (variant_accessor
,
504 pattern
->get_locus ());
506 ctx
->insert_pattern_binding (
507 pattern
->get_mappings ().get_hirid (), binding
);
516 CompilePatternBindings::visit (HIR::StructPattern
&pattern
)
519 TyTy::BaseType
*lookup
= nullptr;
520 bool ok
= ctx
->get_tyctx ()->lookup_type (
521 pattern
.get_path ().get_mappings ().get_hirid (), &lookup
);
524 // this must be an enum
525 rust_assert (lookup
->get_kind () == TyTy::TypeKind::ADT
);
526 TyTy::ADTType
*adt
= static_cast<TyTy::ADTType
*> (lookup
);
527 rust_assert (adt
->number_of_variants () > 0);
529 int variant_index
= 0;
530 TyTy::VariantDef
*variant
= adt
->get_variants ().at (0);
533 HirId variant_id
= UNKNOWN_HIRID
;
534 bool ok
= ctx
->get_tyctx ()->lookup_variant_definition (
535 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
538 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
, &variant_index
);
542 rust_assert (variant
->get_variant_type ()
543 == TyTy::VariantDef::VariantType::STRUCT
);
545 auto &struct_pattern_elems
= pattern
.get_struct_pattern_elems ();
546 for (auto &field
: struct_pattern_elems
.get_struct_pattern_fields ())
548 switch (field
->get_item_type ())
550 case HIR::StructPatternField::ItemType::TUPLE_PAT
: {
556 case HIR::StructPatternField::ItemType::IDENT_PAT
: {
562 case HIR::StructPatternField::ItemType::IDENT
: {
563 HIR::StructPatternFieldIdent
&ident
564 = static_cast<HIR::StructPatternFieldIdent
&> (*field
.get ());
567 ok
= variant
->lookup_field (ident
.get_identifier ().as_string (),
571 tree binding
= error_mark_node
;
574 tree variant_accessor
575 = Backend::struct_field_expression (match_scrutinee_expr
,
579 // we are offsetting by + 1 here since the first field in the
580 // record is always the discriminator
581 binding
= Backend::struct_field_expression (variant_accessor
,
587 tree variant_accessor
= match_scrutinee_expr
;
589 = Backend::struct_field_expression (variant_accessor
, offs
,
593 ctx
->insert_pattern_binding (ident
.get_mappings ().get_hirid (),
602 CompilePatternBindings::visit (HIR::ReferencePattern
&pattern
)
605 = indirect_expression (match_scrutinee_expr
, pattern
.get_locus ());
607 CompilePatternBindings::Compile (pattern
.get_referenced_pattern ().get (),
612 CompilePatternBindings::visit (HIR::IdentifierPattern
&pattern
)
614 ctx
->insert_pattern_binding (pattern
.get_mappings ().get_hirid (),
615 match_scrutinee_expr
);
619 CompilePatternLet::visit (HIR::IdentifierPattern
&pattern
)
621 Bvariable
*var
= nullptr;
623 ctx
->lookup_var_decl (pattern
.get_mappings ().get_hirid (), &var
));
625 auto fnctx
= ctx
->peek_fn ();
628 ctx
->add_statement (init_expr
);
630 auto unit_type_init_expr
= unit_expression (ctx
, rval_locus
);
631 auto s
= Backend::init_statement (fnctx
.fndecl
, var
, unit_type_init_expr
);
632 ctx
->add_statement (s
);
636 auto s
= Backend::init_statement (fnctx
.fndecl
, var
, init_expr
);
637 ctx
->add_statement (s
);
642 CompilePatternLet::visit (HIR::WildcardPattern
&pattern
)
644 tree init_stmt
= NULL
;
645 tree stmt_type
= TyTyResolveCompile::compile (ctx
, ty
);
647 Backend::temporary_variable (ctx
->peek_fn ().fndecl
, NULL_TREE
, stmt_type
,
648 init_expr
, false, pattern
.get_locus (),
651 ctx
->add_statement (init_stmt
);
655 CompilePatternLet::visit (HIR::TuplePattern
&pattern
)
657 rust_assert (pattern
.has_tuple_pattern_items ());
659 tree tuple_type
= TyTyResolveCompile::compile (ctx
, ty
);
662 = Backend::temporary_variable (ctx
->peek_fn ().fndecl
, NULL_TREE
,
663 tuple_type
, init_expr
, false,
664 pattern
.get_locus (), &init_stmt
);
665 tree access_expr
= Backend::var_expression (tmp_var
, pattern
.get_locus ());
666 ctx
->add_statement (init_stmt
);
668 switch (pattern
.get_items ()->get_item_type ())
670 case HIR::TuplePatternItems::ItemType::RANGED
: {
671 size_t tuple_idx
= 0;
673 = static_cast<HIR::TuplePatternItemsRanged
&> (*pattern
.get_items ());
675 auto &items_lower
= items
.get_lower_patterns ();
676 auto &items_upper
= items
.get_upper_patterns ();
678 for (auto &sub
: items_lower
)
680 TyTy::BaseType
*ty_sub
= nullptr;
681 HirId sub_id
= sub
->get_mappings ().get_hirid ();
682 bool ok
= ctx
->get_tyctx ()->lookup_type (sub_id
, &ty_sub
);
686 = Backend::struct_field_expression (access_expr
, tuple_idx
,
688 CompilePatternLet::Compile (sub
.get (), sub_init
, ty_sub
,
693 rust_assert (ty
->get_kind () == TyTy::TypeKind::TUPLE
);
694 tuple_idx
= static_cast<TyTy::TupleType
&> (*ty
).num_fields ()
695 - items_upper
.size ();
697 for (auto &sub
: items_upper
)
699 TyTy::BaseType
*ty_sub
= nullptr;
700 HirId sub_id
= sub
->get_mappings ().get_hirid ();
701 bool ok
= ctx
->get_tyctx ()->lookup_type (sub_id
, &ty_sub
);
705 = Backend::struct_field_expression (access_expr
, tuple_idx
,
707 CompilePatternLet::Compile (sub
.get (), sub_init
, ty_sub
,
714 case HIR::TuplePatternItems::ItemType::MULTIPLE
: {
715 size_t tuple_idx
= 0;
716 auto &items
= static_cast<HIR::TuplePatternItemsMultiple
&> (
717 *pattern
.get_items ());
719 for (auto &sub
: items
.get_patterns ())
721 TyTy::BaseType
*ty_sub
= nullptr;
722 HirId sub_id
= sub
->get_mappings ().get_hirid ();
723 bool ok
= ctx
->get_tyctx ()->lookup_type (sub_id
, &ty_sub
);
727 = Backend::struct_field_expression (access_expr
, tuple_idx
,
729 CompilePatternLet::Compile (sub
.get (), sub_init
, ty_sub
,
742 } // namespace Compile