@@ -534,25 +534,14 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
534
534
|| lookup->get_kind () == TyTy::TypeKind::SLICE
535
535
|| lookup->get_kind () == TyTy::REF);
536
536
537
- size_t array_element_index = 0 ;
537
+ // function ptr that points to either array_index_expression or
538
+ // slice_index_expression depending on the scrutinee's type
539
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t ) = nullptr ;
540
+
538
541
switch (lookup->get_kind ())
539
542
{
540
543
case TyTy::TypeKind::ARRAY:
541
- for (auto &pattern_member : pattern.get_items ())
542
- {
543
- tree array_index_tree
544
- = Backend::size_constant_expression (array_element_index++);
545
- tree element_expr
546
- = Backend::array_index_expression (match_scrutinee_expr,
547
- array_index_tree,
548
- pattern.get_locus ());
549
- tree check_expr_sub
550
- = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
551
- ctx);
552
- check_expr = Backend::arithmetic_or_logical_expression (
553
- ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
554
- check_expr_sub, pattern.get_locus ());
555
- }
544
+ scrutinee_index_expr_func = Backend::array_index_expression;
556
545
break ;
557
546
case TyTy::TypeKind::SLICE:
558
547
rust_sorry_at (
@@ -562,36 +551,153 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
562
551
case TyTy::TypeKind::REF:
563
552
{
564
553
rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
554
+ scrutinee_index_expr_func = Backend::slice_index_expression;
565
555
tree size_field
566
556
= Backend::struct_field_expression (match_scrutinee_expr, 1 ,
567
557
pattern.get_locus ());
568
558
569
- // First compare the size
570
- check_expr = Backend::comparison_expression (
571
- ComparisonOperator::EQUAL, size_field,
572
- build_int_cst (size_type_node, pattern.get_items ().size ()),
573
- pattern.get_locus ());
559
+ // for slices, generate a dynamic size comparison expression tree
560
+ // because size checking is done at runtime.
561
+ switch (pattern.get_items ().get_item_type ())
562
+ {
563
+ case HIR::SlicePatternItems::ItemType::NO_REST:
564
+ {
565
+ auto &items = static_cast <HIR::SlicePatternItemsNoRest &> (
566
+ pattern.get_items ());
567
+ check_expr = Backend::comparison_expression (
568
+ ComparisonOperator::EQUAL, size_field,
569
+ build_int_cst (size_type_node, items.get_patterns ().size ()),
570
+ pattern.get_locus ());
571
+ }
572
+ break ;
573
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
574
+ {
575
+ auto &items = static_cast <HIR::SlicePatternItemsHasRest &> (
576
+ pattern.get_items ());
577
+ auto pattern_min_cap = items.get_lower_patterns ().size ()
578
+ + items.get_upper_patterns ().size ();
579
+ check_expr = Backend::comparison_expression (
580
+ ComparisonOperator::GREATER_OR_EQUAL, size_field,
581
+ build_int_cst (size_type_node, pattern_min_cap),
582
+ pattern.get_locus ());
583
+ }
584
+ break ;
585
+ }
586
+ }
587
+ break ;
588
+ default :
589
+ rust_unreachable ();
590
+ }
591
+
592
+ rust_assert (scrutinee_index_expr_func != nullptr );
574
593
575
- // Then compare each element in the slice pattern
576
- for (auto &pattern_member : pattern.get_items ())
594
+ // Generate tree to compare every element within array/slice
595
+ size_t element_index = 0 ;
596
+ switch (pattern.get_items ().get_item_type ())
597
+ {
598
+ case HIR::SlicePatternItems::ItemType::NO_REST:
599
+ {
600
+ auto &items
601
+ = static_cast <HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
602
+ for (auto &pattern_member : items.get_patterns ())
577
603
{
578
- tree slice_index_tree
579
- = Backend::size_constant_expression (array_element_index ++);
604
+ tree index_tree
605
+ = Backend::size_constant_expression (element_index ++);
580
606
tree element_expr
581
- = Backend::slice_index_expression (match_scrutinee_expr,
582
- slice_index_tree,
583
- pattern.get_locus ());
607
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
608
+ pattern.get_locus ());
609
+ tree check_expr_sub
610
+ = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
611
+ ctx);
612
+ check_expr = Backend::arithmetic_or_logical_expression (
613
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
614
+ check_expr_sub, pattern.get_locus ());
615
+ }
616
+ break ;
617
+ }
618
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
619
+ {
620
+ auto &items
621
+ = static_cast <HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
622
+ for (auto &pattern_member : items.get_lower_patterns ())
623
+ {
624
+ tree index_tree
625
+ = Backend::size_constant_expression (element_index++);
626
+ tree element_expr
627
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
628
+ pattern.get_locus ());
584
629
tree check_expr_sub
585
630
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
586
631
ctx);
587
632
check_expr = Backend::arithmetic_or_logical_expression (
588
633
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
589
634
check_expr_sub, pattern.get_locus ());
590
635
}
636
+
637
+ // handle codegen for upper patterns differently for both types
638
+ switch (lookup->get_kind ())
639
+ {
640
+ case TyTy::TypeKind::ARRAY:
641
+ {
642
+ // for array type scrutinee, we can simply get the capacity as a
643
+ // const and calculate how many elements to skip
644
+ auto array_ty = static_cast <TyTy::ArrayType *> (lookup);
645
+ auto cap_tree = array_ty->get_capacity ()->get_value ();
646
+ size_t cap_wi = (size_t ) wi::to_wide (cap_tree).to_uhwi ();
647
+ element_index = cap_wi - items.get_upper_patterns ().size ();
648
+ for (auto &pattern_member : items.get_upper_patterns ())
649
+ {
650
+ tree index_tree
651
+ = Backend::size_constant_expression (element_index++);
652
+ tree element_expr
653
+ = scrutinee_index_expr_func (match_scrutinee_expr,
654
+ index_tree,
655
+ pattern.get_locus ());
656
+ tree check_expr_sub
657
+ = CompilePatternCheckExpr::Compile (*pattern_member,
658
+ element_expr, ctx);
659
+ check_expr = Backend::arithmetic_or_logical_expression (
660
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
661
+ check_expr_sub, pattern.get_locus ());
662
+ }
663
+ }
664
+ break ;
665
+ case TyTy::TypeKind::REF:
666
+ {
667
+ // for slice type scrutinee, size is dyanamic, so number of
668
+ // elements to skip is calculated during runtime
669
+ tree slice_size
670
+ = Backend::struct_field_expression (match_scrutinee_expr, 1 ,
671
+ pattern.get_locus ());
672
+ tree upper_patterns_size = Backend::size_constant_expression (
673
+ items.get_upper_patterns ().size ());
674
+ tree index_tree = Backend::arithmetic_or_logical_expression (
675
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
676
+ upper_patterns_size, pattern.get_locus ());
677
+ for (auto &pattern_member : items.get_upper_patterns ())
678
+ {
679
+ tree element_expr
680
+ = scrutinee_index_expr_func (match_scrutinee_expr,
681
+ index_tree,
682
+ pattern.get_locus ());
683
+ tree check_expr_sub
684
+ = CompilePatternCheckExpr::Compile (*pattern_member,
685
+ element_expr, ctx);
686
+ check_expr = Backend::arithmetic_or_logical_expression (
687
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
688
+ check_expr_sub, pattern.get_locus ());
689
+ index_tree = Backend::arithmetic_or_logical_expression (
690
+ ArithmeticOrLogicalOperator::ADD, index_tree,
691
+ Backend::size_constant_expression (1 ),
692
+ pattern.get_locus ());
693
+ }
694
+ }
695
+ break ;
696
+ default :
697
+ rust_unreachable ();
698
+ }
591
699
}
592
700
break ;
593
- default :
594
- rust_unreachable ();
595
701
}
596
702
}
597
703
@@ -932,43 +1038,121 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern)
932
1038
|| lookup->get_kind () == TyTy::TypeKind::SLICE
933
1039
|| lookup->get_kind () == TyTy::REF);
934
1040
935
- size_t array_element_index = 0 ;
1041
+ // function ptr that points to either array_index_expression or
1042
+ // slice_index_expression depending on the scrutinee's type
1043
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t ) = nullptr ;
1044
+
936
1045
switch (lookup->get_kind ())
937
1046
{
938
1047
case TyTy::TypeKind::ARRAY:
939
- for (auto &pattern_member : pattern.get_items ())
940
- {
941
- tree array_index_tree
942
- = Backend::size_constant_expression (array_element_index++);
943
- tree element_expr
944
- = Backend::array_index_expression (match_scrutinee_expr,
945
- array_index_tree,
946
- pattern.get_locus ());
947
- CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
948
- }
1048
+ scrutinee_index_expr_func = Backend::array_index_expression;
949
1049
break ;
950
1050
case TyTy::TypeKind::SLICE:
951
- rust_sorry_at (
952
- pattern. get_locus (),
953
- " SlicePattern matching against non-ref slices are not yet supported" );
1051
+ rust_sorry_at (pattern. get_locus (),
1052
+ " SlicePattern matching against non-ref slices are "
1053
+ " not yet supported" );
954
1054
break ;
955
1055
case TyTy::TypeKind::REF:
1056
+ scrutinee_index_expr_func = Backend::slice_index_expression;
1057
+ break ;
1058
+ default :
1059
+ rust_unreachable ();
1060
+ }
1061
+
1062
+ rust_assert (scrutinee_index_expr_func != nullptr );
1063
+
1064
+ size_t element_index = 0 ;
1065
+
1066
+ switch (pattern.get_items ().get_item_type ())
1067
+ {
1068
+ case HIR::SlicePatternItems::ItemType::NO_REST:
956
1069
{
957
- for (auto &pattern_member : pattern.get_items ())
1070
+ auto &items
1071
+ = static_cast <HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
1072
+ for (auto &pattern_member : items.get_patterns ())
958
1073
{
959
- tree slice_index_tree
960
- = Backend::size_constant_expression (array_element_index ++);
1074
+ tree index_tree
1075
+ = Backend::size_constant_expression (element_index ++);
961
1076
tree element_expr
962
- = Backend::slice_index_expression (match_scrutinee_expr,
963
- slice_index_tree,
964
- pattern.get_locus ());
1077
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1078
+ pattern.get_locus ());
965
1079
CompilePatternBindings::Compile (*pattern_member, element_expr,
966
1080
ctx);
967
1081
}
968
- break ;
969
1082
}
970
- default :
971
- rust_unreachable ();
1083
+ break ;
1084
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
1085
+ {
1086
+ auto &items
1087
+ = static_cast <HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
1088
+ for (auto &pattern_member : items.get_lower_patterns ())
1089
+ {
1090
+ tree index_tree
1091
+ = Backend::size_constant_expression (element_index++);
1092
+ tree element_expr
1093
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
1094
+ pattern.get_locus ());
1095
+ CompilePatternBindings::Compile (*pattern_member, element_expr,
1096
+ ctx);
1097
+ }
1098
+
1099
+ // handle codegen for upper patterns differently for both types
1100
+ switch (lookup->get_kind ())
1101
+ {
1102
+ case TyTy::TypeKind::ARRAY:
1103
+ {
1104
+ auto array_ty = static_cast <TyTy::ArrayType *> (lookup);
1105
+ auto cap_tree = array_ty->get_capacity ()->get_value ();
1106
+ size_t cap_wi = (size_t ) wi::to_wide (cap_tree).to_uhwi ();
1107
+ element_index = cap_wi - items.get_upper_patterns ().size ();
1108
+ for (auto &pattern_member : items.get_upper_patterns ())
1109
+ {
1110
+ tree index_tree
1111
+ = Backend::size_constant_expression (element_index++);
1112
+ tree element_expr
1113
+ = scrutinee_index_expr_func (match_scrutinee_expr,
1114
+ index_tree,
1115
+ pattern.get_locus ());
1116
+ CompilePatternBindings::Compile (*pattern_member,
1117
+ element_expr, ctx);
1118
+ }
1119
+ }
1120
+ break ;
1121
+ case TyTy::TypeKind::SLICE:
1122
+ rust_sorry_at (pattern.get_locus (),
1123
+ " SlicePattern matching against non-ref slices are "
1124
+ " not yet supported" );
1125
+ break ;
1126
+ case TyTy::TypeKind::REF:
1127
+ {
1128
+ tree slice_size
1129
+ = Backend::struct_field_expression (match_scrutinee_expr, 1 ,
1130
+ pattern.get_locus ());
1131
+ tree upper_patterns_size = Backend::size_constant_expression (
1132
+ items.get_upper_patterns ().size ());
1133
+ tree index_tree = Backend::arithmetic_or_logical_expression (
1134
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
1135
+ upper_patterns_size, pattern.get_locus ());
1136
+ for (auto &pattern_member : items.get_upper_patterns ())
1137
+ {
1138
+ tree element_expr
1139
+ = scrutinee_index_expr_func (match_scrutinee_expr,
1140
+ index_tree,
1141
+ pattern.get_locus ());
1142
+ CompilePatternBindings::Compile (*pattern_member,
1143
+ element_expr, ctx);
1144
+ index_tree = Backend::arithmetic_or_logical_expression (
1145
+ ArithmeticOrLogicalOperator::ADD, index_tree,
1146
+ Backend::size_constant_expression (1 ),
1147
+ pattern.get_locus ());
1148
+ }
1149
+ }
1150
+ break ;
1151
+ default :
1152
+ rust_unreachable ();
1153
+ }
1154
+ }
1155
+ break ;
972
1156
}
973
1157
}
974
1158
0 commit comments