Fork of daniellemaywood.uk/gleam — Wasm codegen work
16 kB
1110 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2021 The Gleam contributors
3
4use crate::assert_js;
5
6#[test]
7fn case_on_error() {
8 assert_js!(
9 r#"
10fn a_result() { Error(1) }
11
12pub fn main() {
13 case a_result() {
14 Error(_) -> 1
15 _ -> 2
16 }
17}"#
18 );
19}
20
21#[test]
22fn tuple_and_guard() {
23 assert_js!(
24 r#"
25pub fn go(x) {
26 case #(1, 2) {
27 #(1, a) if a == 2 -> 1
28 #(_, _) -> 2
29 }
30}
31"#,
32 )
33}
34
35#[test]
36fn guard_variable_only_brought_into_scope_when_needed() {
37 assert_js!(
38 r#"
39pub fn go(x) {
40 case x {
41 // We want `a` to be defined before the guard check, and
42 // `b` to be defined only if the predicate on a matches!
43 [a, b] if a == 1 -> a + b
44 _ -> 2
45 }
46}
47"#
48 )
49}
50
51// https://github.com/gleam-lang/gleam/issues/4221
52#[test]
53fn guard_variable_only_brought_into_scope_when_needed_1() {
54 assert_js!(
55 r#"
56pub fn main() {
57 case 1 {
58 i if i == 1 -> True
59 i if i < 2 -> True
60 _ -> False
61 }
62}
63"#
64 )
65}
66
67// https://github.com/gleam-lang/gleam/issues/1187
68#[test]
69fn pointless() {
70 assert_js!(
71 r#"
72pub fn go(x) {
73 case x {
74 _ -> x
75 }
76}
77"#,
78 )
79}
80
81// https://github.com/gleam-lang/gleam/issues/1188
82#[test]
83fn following_todo() {
84 assert_js!(
85 r#"
86pub fn go(x) {
87 case x {
88 True -> todo
89 _ -> 1
90 }
91}
92"#,
93 )
94}
95
96#[test]
97fn multi_subject_catch_all() {
98 assert_js!(
99 r#"
100pub fn go(x, y) {
101 case x, y {
102 True, True -> 1
103 _, _ -> 0
104 }
105}
106"#,
107 )
108}
109
110#[test]
111fn multi_subject_or() {
112 assert_js!(
113 r#"
114pub fn go(x, y) {
115 case x, y {
116 True, _ | _, True -> 1
117 _, _ -> 0
118 }
119}
120"#,
121 )
122}
123
124#[test]
125fn multi_subject_no_catch_all() {
126 assert_js!(
127 r#"
128pub fn go(x, y) {
129 case x, y {
130 True, _ -> 1
131 _, True -> 2
132 False, False -> 0
133 }
134}
135"#,
136 )
137}
138
139#[test]
140fn multi_subject_subject_assignments() {
141 assert_js!(
142 r#"
143pub fn go() {
144 case True, False {
145 True, True -> 1
146 _, _ -> 0
147 }
148}
149"#,
150 )
151}
152
153#[test]
154fn assignment() {
155 assert_js!(
156 r#"
157pub fn go(x) {
158 let y = case x {
159 True -> 1
160 _ -> 0
161 }
162 y
163}
164"#,
165 )
166}
167
168#[test]
169fn preassign_assignment() {
170 assert_js!(
171 r#"
172pub fn go(x) {
173 let y = case x() {
174 True -> 1
175 _ -> 0
176 }
177 y
178}
179"#,
180 )
181}
182
183// https://github.com/gleam-lang/gleam/issues/1237
184#[test]
185fn pipe() {
186 assert_js!(
187 r#"
188pub fn go(x, f) {
189 case x |> f {
190 0 -> 1
191 _ -> 2
192 }
193}
194"#,
195 )
196}
197
198#[test]
199fn result() {
200 assert_js!(
201 r#"
202pub fn go(x) {
203 case x {
204 Ok(_) -> 1
205 Error(_) -> 0
206 }
207}
208"#,
209 )
210}
211
212// https://github.com/gleam-lang/gleam/issues/1506
213#[test]
214fn called_case() {
215 assert_js!(
216 r#"
217pub fn go(x, y) {
218 case x {
219 0 -> y
220 _ -> y
221 }()
222}
223"#,
224 )
225}
226
227// https://github.com/gleam-lang/gleam/issues/1978
228#[test]
229fn case_local_var_in_tuple() {
230 assert_js!(
231 r#"
232pub fn go(x, y) {
233 let z = False
234 case True {
235 x if #(x, z) == #(True, False) -> x
236 _ -> False
237 }
238}
239"#,
240 )
241}
242
243// https://github.com/gleam-lang/gleam/issues/2665
244#[test]
245fn case_branches_guards_are_wrapped_in_parentheses() {
246 assert_js!(
247 r#"
248pub fn anything() -> a {
249 case [] {
250 [a] if False || True -> a
251 _ -> anything()
252 }
253}
254"#,
255 )
256}
257
258// https://github.com/gleam-lang/gleam/issues/2759
259#[test]
260fn nested_string_prefix_match() {
261 assert_js!(
262 r#"
263pub fn main() {
264 case Ok(["a", "b c", "d"]) {
265 Ok(["a", "b " <> _, "d"]) -> 1
266 _ -> 1
267 }
268}
269"#
270 );
271}
272
273// https://github.com/gleam-lang/gleam/issues/2759
274#[test]
275fn nested_string_prefix_match_that_would_crash_on_js() {
276 assert_js!(
277 r#"
278pub fn main() {
279 case Ok(["b c", "d"]) {
280 Ok(["b " <> _, "d"]) -> 1
281 _ -> 1
282 }
283}
284"#
285 );
286}
287
288#[test]
289fn slicing_is_handled_properly_with_multiple_branches() {
290 assert_js!(
291 r#"
292pub fn main() {
293 case "12345" {
294 "0" <> rest -> rest
295 "123" <> rest -> rest
296 _ -> ""
297 }
298}
299"#
300 )
301}
302
303// https://github.com/gleam-lang/gleam/issues/3379
304#[test]
305fn single_clause_variables() {
306 assert_js!(
307 r#"
308pub fn main() {
309 let text = "first defined"
310 case "defined again" {
311 text -> Nil
312 }
313 let text = "a third time"
314}
315"#
316 )
317}
318
319// https://github.com/gleam-lang/gleam/issues/3379
320#[test]
321fn single_clause_variables_assigned() {
322 assert_js!(
323 r#"
324pub fn main() {
325 let text = "first defined"
326 let other = case "defined again" {
327 text -> Nil
328 }
329 let text = "a third time"
330}
331"#
332 )
333}
334
335// https://github.com/gleam-lang/gleam/issues/3894
336#[test]
337fn nested_string_prefix_assignment() {
338 assert_js!(
339 r#"
340type Wibble {
341 Wibble(wobble: String)
342}
343
344pub fn main() {
345 let tmp = Wibble(wobble: "wibble")
346 case tmp {
347 Wibble(wobble: "w" as wibble <> rest) -> wibble <> rest
348 _ -> panic
349 }
350}
351"#
352 )
353}
354
355#[test]
356fn deeply_nested_string_prefix_assignment() {
357 assert_js!(
358 r#"
359type Wibble {
360 Wibble(Wobble)
361}
362type Wobble {
363 Wobble(wabble: Wabble)
364}
365type Wabble {
366 Wabble(tuple: #(Int, String))
367}
368
369pub fn main() {
370 let tmp = Wibble(Wobble(Wabble(#(42, "wibble"))))
371 case tmp {
372 Wibble(Wobble(Wabble(#(_int, "w" as wibble <> rest)))) -> wibble <> rest
373 _ -> panic
374 }
375}
376"#
377 )
378}
379
380// https://github.com/gleam-lang/gleam/issues/4383
381#[test]
382fn record_update_in_pipeline_in_case_clause() {
383 assert_js!(
384 "
385pub type Wibble {
386 Wibble(wibble: Int, wobble: Int)
387}
388
389fn identity(x) {
390 x
391}
392
393pub fn go(x) {
394 case x {
395 Wibble(1, _) -> Wibble(..x, wibble: 4) |> identity
396 Wibble(_, 3) -> Wibble(..x, wobble: 10) |> identity
397 _ -> panic
398 }
399}
400"
401 );
402}
403
404#[test]
405fn pattern_matching_on_aliased_result_constructor() {
406 assert_js!(
407 "
408import gleam.{Error as E, Ok as O}
409
410pub fn go(x) {
411 case x {
412 E(_) -> 1
413 O(_) -> 2
414 }
415}
416"
417 );
418}
419
420#[test]
421fn list_with_guard() {
422 assert_js!(
423 "
424pub fn go(x) {
425 case x {
426 [] -> 0
427 [first, ..] if first < 10 -> first * 2
428 [first, ..] -> first
429 }
430}
431"
432 );
433}
434
435#[test]
436fn list_with_guard_no_binding() {
437 assert_js!(
438 "
439pub fn go(x) {
440 case x {
441 [] -> 0
442 [first, ..] if 1 < 10 -> first * 2
443 [first, ..] -> first
444 }
445}
446"
447 );
448}
449
450#[test]
451fn case_building_simple_value_matched_by_pattern() {
452 assert_js!(
453 "pub fn go(x) {
454 case x {
455 1 -> 2
456 n -> n
457 }
458}"
459 )
460}
461
462#[test]
463fn case_building_list_matched_by_pattern() {
464 assert_js!(
465 "pub fn go(x) {
466 case x {
467 [] -> []
468 [a, b] -> [a, b]
469 [1, ..rest] -> [1, ..rest]
470 _ -> x
471 }
472}"
473 )
474}
475
476#[test]
477fn case_building_record_matched_by_pattern() {
478 assert_js!(
479 "pub fn go(x) {
480 case x {
481 Ok(1) -> Ok(1)
482 Ok(n) -> Ok(n)
483 Error(_) -> Error(Nil)
484 }
485}"
486 )
487}
488
489#[test]
490fn case_building_record_with_select_matched_by_pattern() {
491 assert_js!(
492 "
493import gleam
494
495pub fn go(x) {
496 case x {
497 Ok(1) -> gleam.Ok(1)
498 _ -> Error(Nil)
499 }
500}"
501 )
502}
503
504#[test]
505fn case_building_record_with_select_matched_by_pattern_2() {
506 assert_js!(
507 "
508import gleam
509
510pub fn go(x) {
511 case x {
512 gleam.Ok(1) -> gleam.Ok(1)
513 _ -> Error(Nil)
514 }
515}"
516 )
517}
518
519#[test]
520fn case_building_record_with_select_matched_by_pattern_3() {
521 assert_js!(
522 "
523import gleam
524
525pub fn go(x) {
526 case x {
527 gleam.Ok(1) -> Ok(1)
528 _ -> Error(Nil)
529 }
530}"
531 )
532}
533
534#[test]
535fn case_building_matched_string_1() {
536 assert_js!(
537 r#"
538import gleam
539
540pub fn go(x) {
541 case x {
542 "a" <> rest -> "a" <> rest
543 _ -> ""
544 }
545}"#
546 )
547}
548
549#[test]
550fn case_building_matched_string_2() {
551 assert_js!(
552 r#"
553import gleam
554
555pub fn go(x) {
556 case x {
557 "a" as a <> rest -> a <> rest
558 _ -> ""
559 }
560}"#
561 )
562}
563
564#[test]
565fn case_building_matched_value_wrapped_in_block() {
566 assert_js!(
567 r#"
568import gleam
569
570pub fn go(x) {
571 case x {
572 1 -> { 1 }
573 _ -> 2
574 }
575}"#
576 )
577}
578
579#[test]
580fn case_building_matched_value_alias() {
581 assert_js!(
582 r#"
583import gleam
584
585pub fn go(x) {
586 case x {
587 Ok(_) as a -> a
588 Error(Nil) -> Error(Nil)
589 }
590}"#
591 )
592}
593
594#[test]
595fn case_building_matched_value_alias_2() {
596 assert_js!(
597 r#"
598import gleam
599
600pub fn go(x) {
601 case x {
602 Ok(1) as a -> Ok(1)
603 Ok(_) -> Ok(2)
604 Error(Nil) -> Error(Nil)
605 }
606}"#
607 )
608}
609
610#[test]
611fn case_building_matched_value_alias_3() {
612 assert_js!(
613 r#"
614import gleam
615
616pub fn go(x) {
617 case x {
618 Ok(1 as a) -> Ok(a)
619 Ok(_) -> Ok(2)
620 Error(Nil) -> Error(Nil)
621 }
622}"#
623 )
624}
625
626#[test]
627fn case_building_matched_no_variant_record() {
628 assert_js!(
629 r#"
630pub fn go(x) {
631 case x {
632 Ok(Nil) -> Ok(Nil)
633 _ -> Error(Nil)
634 }
635}"#
636 )
637}
638
639#[test]
640fn case_building_matched_no_variant_record_2() {
641 assert_js!(
642 r#"
643import gleam
644
645pub fn go(x) {
646 case x {
647 Ok(gleam.Nil) -> Ok(Nil)
648 _ -> Error(Nil)
649 }
650}"#
651 )
652}
653
654#[test]
655fn case_building_matched_no_variant_record_3() {
656 assert_js!(
657 r#"
658import gleam
659
660pub fn go(x) {
661 case x {
662 Ok(Nil) -> Ok(gleam.Nil)
663 _ -> Error(Nil)
664 }
665}"#
666 )
667}
668
669#[test]
670fn case_building_matched_no_variant_record_4() {
671 assert_js!(
672 r#"
673import gleam
674
675pub fn go(x) {
676 case x {
677 Ok(gleam.Nil) -> Ok(gleam.Nil)
678 _ -> Error(Nil)
679 }
680}"#
681 )
682}
683
684#[test]
685fn case_building_record_with_labels_matched_by_pattern_1() {
686 assert_js!(
687 "
688pub type Wibble {
689 Wibble(int: Int, string: String)
690 Wobble(Int)
691}
692
693pub fn go(x) {
694 case x {
695 Wibble(1, s) -> Wibble(1, s)
696 _ -> Wobble(1)
697 }
698}"
699 )
700}
701
702#[test]
703fn case_building_record_with_labels_matched_by_pattern_2() {
704 assert_js!(
705 "
706pub type Wibble {
707 Wibble(int: Int, string: String)
708 Wobble(Int)
709}
710
711pub fn go(x) {
712 case x {
713 Wibble(string:, int:) -> Wibble(string:, int:)
714 _ -> Wobble(1)
715 }
716}"
717 )
718}
719
720#[test]
721fn case_building_record_with_labels_matched_by_pattern_3() {
722 assert_js!(
723 "
724pub type Wibble {
725 Wibble(int: Int, string: String)
726 Wobble(Int)
727}
728
729pub fn go(x) {
730 case x {
731 // This should not be optimised away!
732 Wibble(string:, int:) -> Wibble(string:, int: 1)
733 _ -> Wobble(1)
734 }
735}"
736 )
737}
738
739#[test]
740fn case_building_record_with_labels_matched_by_pattern_4() {
741 assert_js!(
742 "
743pub type Wibble {
744 Wibble(int: Int, string: String)
745 Wobble(Int)
746}
747
748pub fn go(x) {
749 case x {
750 Wibble(string:, int:) -> Wibble(int:, string:)
751 _ -> Wobble(1)
752 }
753}"
754 )
755}
756
757#[test]
758fn case_building_record_with_labels_matched_by_pattern_5() {
759 assert_js!(
760 "
761pub type Wibble {
762 Wibble(int: Int, string: String)
763 Wobble(Int)
764}
765
766pub fn go(x) {
767 case x {
768 Wibble(string:, int: 1) -> Wibble(1, string:)
769 _ -> Wobble(1)
770 }
771}"
772 )
773}
774
775#[test]
776fn case_building_record_with_labels_matched_by_pattern_6() {
777 assert_js!(
778 "
779pub type Wibble {
780 Wibble(int: Int, string: String)
781 Wobble(Int)
782}
783
784pub fn go(x) {
785 case x {
786 Wibble(1, string:) -> Wibble(string:, int: 1)
787 _ -> Wobble(1)
788 }
789}"
790 )
791}
792
793#[test]
794fn case_with_multiple_subjects_building_simple_value_matched_by_pattern() {
795 assert_js!(
796 "pub fn go(x) {
797 case x, x + 1 {
798 1, _ -> 2
799 _, n -> n
800 }
801}"
802 )
803}
804
805#[test]
806fn case_with_multiple_subjects_building_list_matched_by_pattern() {
807 assert_js!(
808 "pub fn go(n, x) {
809 case n, x {
810 1, [] -> []
811 _, [a, b] -> [a, b]
812 3, [1, ..rest] -> [1, ..rest]
813 _, _ -> x
814 }
815}"
816 )
817}
818
819#[test]
820fn case_with_multiple_subjects_building_record_matched_by_pattern() {
821 assert_js!(
822 "pub fn go(x, y) {
823 case x, y {
824 Ok(1), Error(_) -> Ok(1)
825 Error(_), Ok(n) -> Ok(n)
826 _, _ -> Error(Nil)
827 }
828}"
829 )
830}
831
832#[test]
833fn case_with_multiple_subjects_building_same_value_as_two_subjects_one_is_picked() {
834 assert_js!(
835 "
836import gleam
837
838pub fn go(x, y) {
839 case x, y {
840 gleam.Ok(1), Ok(1) -> Ok(1)
841 _, Error(Nil) -> Error(Nil)
842 _, _ -> Error(Nil)
843 }
844}"
845 )
846}
847
848#[test]
849fn interfering_string_pattern_succeeds_if_succeeding() {
850 assert_js!(
851 r#"
852pub fn wibble(bits) {
853 case bits {
854 <<"aaa", 0, _:bits>> -> 1
855 // If the first one succeeds, so will the second check, so it won't be
856 // performed twice inside the first if branch!
857 <<"aaa", 1, _:bits>> -> 2
858 _ -> 3
859 }
860}"#
861 );
862}
863
864#[test]
865fn string_concatenation_in_clause_guards() {
866 assert_js!(
867 r#"
868pub fn main() {
869 let wibble = "wob"
870 case wibble {
871 x if x <> "ble" == "wobble" -> 1
872 _ -> 0
873 }
874}"#
875 );
876}
877
878#[test]
879fn var_true() {
880 assert_js!(
881 r#"
882fn true() { True }
883pub fn main() {
884 let true_ = true()
885 assert 0 == case Nil {
886 _ if true_ -> 0
887 _ -> 1
888 }
889}
890"#
891 )
892}
893
894#[test]
895// https://github.com/gleam-lang/gleam/issues/5283
896fn duplicate_name_for_variables_used_in_guards() {
897 assert_js!(
898 r#"
899pub fn wibble() {
900 let a = case 1337 {
901 n if n == 1347 -> Nil
902 _ -> Nil
903 }
904 let b = case 1337 {
905 n -> Nil
906 }
907}"#
908 )
909}
910
911#[test]
912// https://github.com/gleam-lang/gleam/issues/5283
913fn duplicate_name_for_variables_used_in_guards_shadowing_outer_name() {
914 assert_js!(
915 r#"
916pub fn wibble() {
917 let n = 1
918 let a = case 1337 {
919 n if n == 1347 -> n
920 _ -> n
921 }
922 let b = case 1337 {
923 n -> Nil
924 }
925}"#
926 )
927}
928
929#[test]
930fn directly_matching_case_subject() {
931 assert_js!(
932 r#"
933pub fn go() {
934 let x = "ABC"
935 case True {
936 True -> {
937 let x = 79
938 0
939 }
940 False -> {
941 let x = True
942 0
943 }
944 }
945 x
946}"#
947 )
948}
949
950// https://github.com/gleam-lang/gleam/issues/5400
951#[test]
952fn case_matching_single_character_prefixes() {
953 assert_js!(
954 r#"
955pub fn parse_digit(s: String) -> Int {
956 case s {
957 "0" <> s -> 0
958 "1" <> s -> 1
959 "2" <> s -> 2
960 "3" <> s -> 3
961 "4" <> s -> 4
962 "5" <> s -> 5
963 "6" <> s -> 6
964 "7" <> s -> 7
965 "8" <> s -> 8
966 "9" <> s -> 9
967 "" -> todo
968 _ -> panic
969 }
970}
971"#
972 );
973}
974
975// https://github.com/gleam-lang/gleam/issues/5467
976#[test]
977fn no_duplicate_let_after_directly_matching_case() {
978 assert_js!(
979 r#"
980pub fn go() {
981 let x =
982 case #(1, 2) {
983 #(1, b) -> b
984 #(_, b) -> b
985 }
986
987 let #(a, _b) = #(x, 3)
988
989 a
990}"#
991 )
992}
993
994// https://github.com/gleam-lang/gleam/issues/5743
995#[test]
996fn no_duplicate_pipe_variable_with_case_in_pipeline() {
997 assert_js!(
998 r#"
999pub fn main() {
1000 0
1001 |> case True {
1002 True -> add_one |> identity
1003 False -> add_one
1004 }
1005 |> add_one
1006}
1007
1008fn identity(x) {
1009 x
1010}
1011
1012fn add_one(x) {
1013 x + 1
1014}"#
1015 )
1016}
1017
1018#[test]
1019fn list_with_tail_used_in_guard() {
1020 assert_js!(
1021 r#"
1022pub fn go(x: List(Int), y: List(Int)) {
1023 case x {
1024 [1, ..x] if [1, 2, ..x] == y -> True
1025 _ -> False
1026 }
1027}"#
1028 )
1029}
1030
1031// https://github.com/gleam-lang/gleam/issues/5612
1032#[test]
1033fn no_duplicate_let_after_case_with_same_named_variable_with_declaration_before_and_after() {
1034 assert_js!(
1035 r#"
1036pub fn go() {
1037 let x = 0
1038 let x = x
1039 let x = case #(1, 2) {
1040 #(_, x) -> x
1041 }
1042
1043 let x = x
1044 x
1045}"#
1046 )
1047}
1048
1049// https://github.com/gleam-lang/gleam/issues/5612
1050#[test]
1051fn no_duplicate_let_after_case_with_same_named_variable() {
1052 assert_js!(
1053 r#"
1054pub fn go() {
1055 let x = case #(1, 2) {
1056 #(_, x) -> x
1057 }
1058
1059 x
1060}"#
1061 )
1062}
1063
1064// https://github.com/gleam-lang/gleam/issues/5748
1065#[test]
1066fn no_duplicate_let_when_rebinding_variable_after_directly_matching_case() {
1067 assert_js!(
1068 r#"
1069pub fn go() {
1070 let n = 1
1071 case True {
1072 True -> {
1073 let n = 99
1074 n
1075 }
1076 False -> 0
1077 }
1078 let n = n + 5
1079 n
1080}"#
1081 )
1082}
1083
1084#[test]
1085fn semicolon_exists_with_directly_matching_case() {
1086 assert_js!(
1087 r#"
1088pub fn go() {
1089 case #(1, 2) {
1090 #(a, _) -> a
1091 }
1092 {2 + 4} * 2
1093}"#
1094 )
1095}
1096
1097#[test]
1098fn semicolon_exists_with_case() {
1099 assert_js!(
1100 r#"
1101pub fn go() {
1102 case #(1, 2) {
1103 #(2, b) -> b
1104 #(1, 3) -> 2
1105 #(a, _) -> a
1106 }
1107 {2 + 4} * 2
1108}"#
1109 )
1110}