aboutsummaryrefslogtreecommitdiff
path: root/tests/conformance/4-statements
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 15:37:28 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 15:39:03 +0330
commita275919ea9141a9d8c966ccef040666d9bda3b60 (patch)
tree5de0bf209aba110f3c80499bb1ceaa5068089b0a /tests/conformance/4-statements
parenttodo: record each agent's state at the end of the session and the merge order (diff)
agent/spec-conformance: unmerged work from previous session
Diffstat (limited to 'tests/conformance/4-statements')
-rw-r--r--tests/conformance/4-statements/asm_arith_mnemonics.zc11
-rw-r--r--tests/conformance/4-statements/asm_constant_name.zc6
-rw-r--r--tests/conformance/4-statements/asm_expression_value.zc5
-rw-r--r--tests/conformance/4-statements/asm_float_literal.zc7
-rw-r--r--tests/conformance/4-statements/asm_function_name.zc6
-rw-r--r--tests/conformance/4-statements/asm_negative_literal.zc5
-rw-r--r--tests/conformance/4-statements/asm_statement_local.zc5
-rw-r--r--tests/conformance/4-statements/asm_string_pushes_address.zc5
-rw-r--r--tests/conformance/4-statements/asm_unknown_name.zc5
-rw-r--r--tests/conformance/4-statements/break_inner_loop_only.zc12
-rw-r--r--tests/conformance/4-statements/break_outside.zc5
-rw-r--r--tests/conformance/4-statements/checked_owned_never_used.zc9
-rw-r--r--tests/conformance/4-statements/continue_in_switch_outside_loop.zc5
-rw-r--r--tests/conformance/4-statements/continue_outside.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_assign.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_increment.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_local_typed_float.zc6
-rw-r--r--tests/conformance/4-statements/decl_const_takes_initializer_type.zc6
-rw-r--r--tests/conformance/4-statements/decl_for_init_scope.zc5
-rw-r--r--tests/conformance/4-statements/decl_for_let_init_scope.zc5
-rw-r--r--tests/conformance/4-statements/decl_let_array.zc10
-rw-r--r--tests/conformance/4-statements/decl_let_bstr.zc9
-rw-r--r--tests/conformance/4-statements/decl_let_char_ptr.zc9
-rw-r--r--tests/conformance/4-statements/decl_let_float_local.zc10
-rw-r--r--tests/conformance/4-statements/decl_let_function_type.zc6
-rw-r--r--tests/conformance/4-statements/decl_let_integer_is_word.zc5
-rw-r--r--tests/conformance/4-statements/decl_let_multiple.zc10
-rw-r--r--tests/conformance/4-statements/decl_redeclare_same_block.zc5
-rw-r--r--tests/conformance/4-statements/decl_scope_ends_with_block.zc5
-rw-r--r--tests/conformance/4-statements/decl_shadow_function_name.zc6
-rw-r--r--tests/conformance/4-statements/decl_shadow_global.zc6
-rw-r--r--tests/conformance/4-statements/decl_shadow_outer_block.zc10
-rw-r--r--tests/conformance/4-statements/decl_shadow_param.zc6
-rw-r--r--tests/conformance/4-statements/decl_tag_only.zc10
-rw-r--r--tests/conformance/4-statements/decl_typed_array_declarator.zc10
-rw-r--r--tests/conformance/4-statements/decl_typed_multi.zc11
-rw-r--r--tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc14
-rw-r--r--tests/conformance/4-statements/decl_uninit_global_is_zero.zc8
-rw-r--r--tests/conformance/4-statements/decl_void_variable.zc5
-rw-r--r--tests/conformance/4-statements/do_basic.zc11
-rw-r--r--tests/conformance/4-statements/do_break.zc6
-rw-r--r--tests/conformance/4-statements/do_continue_jumps_to_test.zc6
-rw-r--r--tests/conformance/4-statements/do_runs_once.zc6
-rw-r--r--tests/conformance/4-statements/for_basic.zc5
-rw-r--r--tests/conformance/4-statements/for_cond_tests_first.zc5
-rw-r--r--tests/conformance/4-statements/for_continue_runs_step.zc10
-rw-r--r--tests/conformance/4-statements/for_empty_parts.zc10
-rw-r--r--tests/conformance/4-statements/for_expression_init.zc5
-rw-r--r--tests/conformance/4-statements/for_let_init.zc5
-rw-r--r--tests/conformance/4-statements/for_variable_is_scoped.zc11
-rw-r--r--tests/conformance/4-statements/hints_forms_accepted.zc9
-rw-r--r--tests/conformance/4-statements/if_basic.zc10
-rw-r--r--tests/conformance/4-statements/if_branch_is_own_scope.zc5
-rw-r--r--tests/conformance/4-statements/if_else_binds_nearest.zc8
-rw-r--r--tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc8
-rw-r--r--tests/conformance/4-statements/if_else_chain.zc9
-rw-r--r--tests/conformance/4-statements/if_float_condition.zc11
-rw-r--r--tests/conformance/4-statements/memdebug_double_free.zc10
-rw-r--r--tests/conformance/4-statements/memdebug_off.zc8
-rw-r--r--tests/conformance/4-statements/memdebug_report.zc15
-rw-r--r--tests/conformance/4-statements/memdebug_report_line.zc15
-rw-r--r--tests/conformance/4-statements/memdebug_scrub_accepted.zc7
-rw-r--r--tests/conformance/4-statements/memdebug_scrub_fills.zc10
-rw-r--r--tests/conformance/4-statements/memdebug_statement_form.zc6
-rw-r--r--tests/conformance/4-statements/memdebug_use_after_free.zc10
-rw-r--r--tests/conformance/4-statements/nested_return_in_loop.zc9
-rw-r--r--tests/conformance/4-statements/o3_asm_cannot_reach.zc6
-rw-r--r--tests/conformance/4-statements/o3_block.zc11
-rw-r--r--tests/conformance/4-statements/o3_fn_form.zc7
-rw-r--r--tests/conformance/4-statements/o3_function_sum.zc13
-rw-r--r--tests/conformance/4-statements/o3_nested_is_ordinary_block.zc6
-rw-r--r--tests/conformance/4-statements/o3_no_address_of.zc6
-rw-r--r--tests/conformance/4-statements/o3_outside_function_ordinary_block.zc7
-rw-r--r--tests/conformance/4-statements/o3_parameter_needs_type.zc7
-rw-r--r--tests/conformance/4-statements/o3_single_variable.zc6
-rw-r--r--tests/conformance/4-statements/o3_variable_needs_type.zc6
-rw-r--r--tests/conformance/4-statements/return_bare_is_zero.zc6
-rw-r--r--tests/conformance/4-statements/return_fall_off_is_zero.zc6
-rw-r--r--tests/conformance/4-statements/return_frees_owned_locals.zc11
-rw-r--r--tests/conformance/4-statements/return_outside_function.zc6
-rw-r--r--tests/conformance/4-statements/return_value_converted_float.zc7
-rw-r--r--tests/conformance/4-statements/return_value_converted_int.zc6
-rw-r--r--tests/conformance/4-statements/return_void_value_typecheck_on.zc7
-rw-r--r--tests/conformance/4-statements/stmt_block_scope.zc5
-rw-r--r--tests/conformance/4-statements/stmt_empty_statement.zc5
-rw-r--r--tests/conformance/4-statements/stmt_expression_value_dropped.zc5
-rw-r--r--tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc5
-rw-r--r--tests/conformance/4-statements/stmt_u_result_thrown_away.zc6
-rw-r--r--tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc13
-rw-r--r--tests/conformance/4-statements/switch_break_leaves_early.zc10
-rw-r--r--tests/conformance/4-statements/switch_case_own_block.zc11
-rw-r--r--tests/conformance/4-statements/switch_case_three.zc10
-rw-r--r--tests/conformance/4-statements/switch_case_underscore.zc7
-rw-r--r--tests/conformance/4-statements/switch_continue_continues_loop.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_and_underscore.zc5
-rw-r--r--tests/conformance/4-statements/switch_default_first_position_not_matched.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_first_position_taken.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_middle.zc7
-rw-r--r--tests/conformance/4-statements/switch_default_runs.zc10
-rw-r--r--tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc10
-rw-r--r--tests/conformance/4-statements/switch_expression_evaluated_once.zc10
-rw-r--r--tests/conformance/4-statements/switch_label_forms.zc16
-rw-r--r--tests/conformance/4-statements/switch_nested.zc14
-rw-r--r--tests/conformance/4-statements/switch_no_fallthrough_k2.zc10
-rw-r--r--tests/conformance/4-statements/switch_no_match_no_default.zc11
-rw-r--r--tests/conformance/4-statements/switch_non_constant_label.zc5
-rw-r--r--tests/conformance/4-statements/switch_return_inside_case.zc6
-rw-r--r--tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_binding_count.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc12
-rw-r--r--tests/conformance/4-statements/switch_tagged_circle.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_default_no_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_example.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_match_by_tag.zc19
-rw-r--r--tests/conformance/4-statements/switch_tagged_uncovered_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc11
-rw-r--r--tests/conformance/4-statements/switch_two_defaults.zc5
-rw-r--r--tests/conformance/4-statements/switch_two_underscores.zc5
-rw-r--r--tests/conformance/4-statements/unchecked_fn.zc6
-rw-r--r--tests/conformance/4-statements/unchecked_fn_does_not_extend.zc6
-rw-r--r--tests/conformance/4-statements/unchecked_stmt_block.zc9
-rw-r--r--tests/conformance/4-statements/unchecked_stmt_single.zc10
-rw-r--r--tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc10
-rw-r--r--tests/conformance/4-statements/unchecked_tracked_local_rejected.zc9
-rw-r--r--tests/conformance/4-statements/while_basic.zc5
-rw-r--r--tests/conformance/4-statements/while_continue.zc10
-rw-r--r--tests/conformance/4-statements/while_one_exit_by_return.zc6
-rw-r--r--tests/conformance/4-statements/while_one_exits_by_break.zc5
-rw-r--r--tests/conformance/4-statements/while_tests_before.zc5
129 files changed, 1042 insertions, 0 deletions
diff --git a/tests/conformance/4-statements/asm_arith_mnemonics.zc b/tests/conformance/4-statements/asm_arith_mnemonics.zc
new file mode 100644
index 0000000..79e06da
--- /dev/null
+++ b/tests/conformance/4-statements/asm_arith_mnemonics.zc
@@ -0,0 +1,11 @@
+// expect: 42/8/14/6/
+// spec 4.13.1: mnemonics * & | ^
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(asm { 6 7 * });
+ pn(asm { 12 10 & });
+ pn(asm { 12 10 | });
+ pn(asm { 12 10 ^ });
+ return 0;
+}
diff --git a/tests/conformance/4-statements/asm_constant_name.zc b/tests/conformance/4-statements/asm_constant_name.zc
new file mode 100644
index 0000000..b27f133
--- /dev/null
+++ b/tests/conformance/4-statements/asm_constant_name.zc
@@ -0,0 +1,6 @@
+// expect: 9/
+// spec 4.13.1: the name of a constant pushes its value
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const K = 9;
+fn main() { pn(asm { K }); return 0; }
diff --git a/tests/conformance/4-statements/asm_expression_value.zc b/tests/conformance/4-statements/asm_expression_value.zc
new file mode 100644
index 0000000..68e483c
--- /dev/null
+++ b/tests/conformance/4-statements/asm_expression_value.zc
@@ -0,0 +1,5 @@
+// expect: 5/
+// spec 4.13.1 example
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { 2 3 + }; pn(x); return 0; }
diff --git a/tests/conformance/4-statements/asm_float_literal.zc b/tests/conformance/4-statements/asm_float_literal.zc
new file mode 100644
index 0000000..dfb1e23
--- /dev/null
+++ b/tests/conformance/4-statements/asm_float_literal.zc
@@ -0,0 +1,7 @@
+// expect: 1.500000/
+// spec 4.13.1: a float literal emits flit and its bits
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { float f = asm { 1.5 }; pf(f); return 0; }
+
diff --git a/tests/conformance/4-statements/asm_function_name.zc b/tests/conformance/4-statements/asm_function_name.zc
new file mode 100644
index 0000000..56d8bad
--- /dev/null
+++ b/tests/conformance/4-statements/asm_function_name.zc
@@ -0,0 +1,6 @@
+// expect: 3/
+// spec 4.13.1: a function name pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int three() { return 3; }
+fn main() { fn() g = asm { three }; pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/asm_negative_literal.zc b/tests/conformance/4-statements/asm_negative_literal.zc
new file mode 100644
index 0000000..ebd8432
--- /dev/null
+++ b/tests/conformance/4-statements/asm_negative_literal.zc
@@ -0,0 +1,5 @@
+// expect: -2/
+// spec 4.13.1: -n pushes a negative
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { -5 3 + }; pn(x); return 0; }
diff --git a/tests/conformance/4-statements/asm_statement_local.zc b/tests/conformance/4-statements/asm_statement_local.zc
new file mode 100644
index 0000000..9b7e985
--- /dev/null
+++ b/tests/conformance/4-statements/asm_statement_local.zc
@@ -0,0 +1,5 @@
+// expect: 8/
+// spec 4.13.1 example: the name of a local pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int y = 7; asm { y @ 1 + y ! } pn(y); return 0; }
diff --git a/tests/conformance/4-statements/asm_string_pushes_address.zc b/tests/conformance/4-statements/asm_string_pushes_address.zc
new file mode 100644
index 0000000..7041996
--- /dev/null
+++ b/tests/conformance/4-statements/asm_string_pushes_address.zc
@@ -0,0 +1,5 @@
+// expect: 104/
+// spec 4.13.1: a string pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = asm { "hi" }; pn(s[0]); return 0; }
diff --git a/tests/conformance/4-statements/asm_unknown_name.zc b/tests/conformance/4-statements/asm_unknown_name.zc
new file mode 100644
index 0000000..f6436a8
--- /dev/null
+++ b/tests/conformance/4-statements/asm_unknown_name.zc
@@ -0,0 +1,5 @@
+// expect error: unknown name in asm
+// spec 4.13.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { nosuchthing }; return 0; }
diff --git a/tests/conformance/4-statements/break_inner_loop_only.zc b/tests/conformance/4-statements/break_inner_loop_only.zc
new file mode 100644
index 0000000..47db8ef
--- /dev/null
+++ b/tests/conformance/4-statements/break_inner_loop_only.zc
@@ -0,0 +1,12 @@
+// expect: 6/
+// spec 4.8.1: break leaves the innermost loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 5; j++) { if (j == 2) break; n++; }
+ }
+ pn(n);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/break_outside.zc b/tests/conformance/4-statements/break_outside.zc
new file mode 100644
index 0000000..6662c16
--- /dev/null
+++ b/tests/conformance/4-statements/break_outside.zc
@@ -0,0 +1,5 @@
+// expect error: break outside a loop or a switch
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { break; return 0; }
diff --git a/tests/conformance/4-statements/checked_owned_never_used.zc b/tests/conformance/4-statements/checked_owned_never_used.zc
new file mode 100644
index 0000000..6c89dee
--- /dev/null
+++ b/tests/conformance/4-statements/checked_owned_never_used.zc
@@ -0,0 +1,9 @@
+// expect error: p: owned object is never used
+// spec 6.5.2 (the checked counterpart of unchecked_toplevel_rest_of_unit)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = rt.new(int);
+ pn(1);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/continue_in_switch_outside_loop.zc b/tests/conformance/4-statements/continue_in_switch_outside_loop.zc
new file mode 100644
index 0000000..eaca865
--- /dev/null
+++ b/tests/conformance/4-statements/continue_in_switch_outside_loop.zc
@@ -0,0 +1,5 @@
+// expect error: continue outside a loop
+// spec 4.8.1 and 4.7.1: continue inside a switch continues the enclosing loop, there is none here
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { case 1: continue; } return 0; }
diff --git a/tests/conformance/4-statements/continue_outside.zc b/tests/conformance/4-statements/continue_outside.zc
new file mode 100644
index 0000000..7d8e808
--- /dev/null
+++ b/tests/conformance/4-statements/continue_outside.zc
@@ -0,0 +1,5 @@
+// expect error: continue outside a loop
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { continue; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_assign.zc b/tests/conformance/4-statements/decl_const_assign.zc
new file mode 100644
index 0000000..63728dc
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_assign.zc
@@ -0,0 +1,5 @@
+// expect error: const storage cannot be modified
+// spec 4.1.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const k = 1; k += 2; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_increment.zc b/tests/conformance/4-statements/decl_const_increment.zc
new file mode 100644
index 0000000..28d7065
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_increment.zc
@@ -0,0 +1,5 @@
+// expect error: const storage cannot be modified
+// spec 4.1.4 and 2.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const k = 1; k++; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_local_typed_float.zc b/tests/conformance/4-statements/decl_const_local_typed_float.zc
new file mode 100644
index 0000000..d8470ae
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_local_typed_float.zc
@@ -0,0 +1,6 @@
+// expect: 3.000000/
+// spec 4.1.4: const T k = e is a typed const
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { const float k = 3; pf(k); return 0; }
diff --git a/tests/conformance/4-statements/decl_const_takes_initializer_type.zc b/tests/conformance/4-statements/decl_const_takes_initializer_type.zc
new file mode 100644
index 0000000..cfe2aec
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_takes_initializer_type.zc
@@ -0,0 +1,6 @@
+// expect: 0.500000/
+// spec 4.1.4 and 2.10.2: a local const takes the type of its initializer (float here)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { const k = 1.5; pf(k - 1); return 0; }
diff --git a/tests/conformance/4-statements/decl_for_init_scope.zc b/tests/conformance/4-statements/decl_for_init_scope.zc
new file mode 100644
index 0000000..7d4cae3
--- /dev/null
+++ b/tests/conformance/4-statements/decl_for_init_scope.zc
@@ -0,0 +1,5 @@
+// expect error: i is used but never defined
+// spec 4.1.8: a for initializer declaration is scoped to the loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { for (int i = 0; i < 2; i++) { } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/decl_for_let_init_scope.zc b/tests/conformance/4-statements/decl_for_let_init_scope.zc
new file mode 100644
index 0000000..1f94e3b
--- /dev/null
+++ b/tests/conformance/4-statements/decl_for_let_init_scope.zc
@@ -0,0 +1,5 @@
+// expect error: i is used but never defined
+// spec 4.6 and 4.1.8
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { for (let i = 0; i < 2; i++) { } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_array.zc b/tests/conformance/4-statements/decl_let_array.zc
new file mode 100644
index 0000000..9d8d701
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_array.zc
@@ -0,0 +1,10 @@
+// expect: 10/3/
+// spec 4.1.2: let a[10]; is an untyped array of 10 words (word[10])
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let a[10];
+ a[9] = 3;
+ pn(sizeof(a)); pn(a[9]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_bstr.zc b/tests/conformance/4-statements/decl_let_bstr.zc
new file mode 100644
index 0000000..c54d0d8
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_bstr.zc
@@ -0,0 +1,9 @@
+// expect: 3/98/
+// spec 4.1.2: bstr from a byte-string literal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let t = b"abc";
+ pn(len(t)); pn(t[1]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_char_ptr.zc b/tests/conformance/4-statements/decl_let_char_ptr.zc
new file mode 100644
index 0000000..4bc7a57
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_char_ptr.zc
@@ -0,0 +1,9 @@
+// expect: 2/105/
+// spec 4.1.2: char* from a word-string literal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let s = "hi";
+ pn(rt.len_w(s)); pn(s[1]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_float_local.zc b/tests/conformance/4-statements/decl_let_float_local.zc
new file mode 100644
index 0000000..118e6a9
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_float_local.zc
@@ -0,0 +1,10 @@
+// expect: 0.750000/
+// spec 4.1.2: a float local from a float initializer, so / is float division
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ let f = 1.5;
+ pf(f / 2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_function_type.zc b/tests/conformance/4-statements/decl_let_function_type.zc
new file mode 100644
index 0000000..9f9d76d
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_function_type.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+// spec 4.1.2: the function type of the initializer
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int add(int a, int b) { return a + b; }
+fn main() { let h = add; pn(h(3, 4)); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_integer_is_word.zc b/tests/conformance/4-statements/decl_let_integer_is_word.zc
new file mode 100644
index 0000000..8159089
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_integer_is_word.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.1.2: a plain word for integers
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { let n = 3; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_multiple.zc b/tests/conformance/4-statements/decl_let_multiple.zc
new file mode 100644
index 0000000..e6ec7d4
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_multiple.zc
@@ -0,0 +1,10 @@
+// expect: 1/2/
+// spec 4.1.2: let a = e, b[10]
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let a = 1, b[4];
+ b[3] = 2;
+ pn(a); pn(b[3]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_redeclare_same_block.zc b/tests/conformance/4-statements/decl_redeclare_same_block.zc
new file mode 100644
index 0000000..e593fb7
--- /dev/null
+++ b/tests/conformance/4-statements/decl_redeclare_same_block.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+// spec 4.1.6: redeclaring a name in the same block is accepted and the new one hides the old one
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; int a = 2; pn(a); return 0; }
diff --git a/tests/conformance/4-statements/decl_scope_ends_with_block.zc b/tests/conformance/4-statements/decl_scope_ends_with_block.zc
new file mode 100644
index 0000000..4d868d7
--- /dev/null
+++ b/tests/conformance/4-statements/decl_scope_ends_with_block.zc
@@ -0,0 +1,5 @@
+// expect error: x is used but never defined
+// spec 4.1.8: a local is scoped to its block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { { int x = 1; } pn(x); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_function_name.zc b/tests/conformance/4-statements/decl_shadow_function_name.zc
new file mode 100644
index 0000000..b7dcdd4
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_function_name.zc
@@ -0,0 +1,6 @@
+// expect: 5/
+// spec 4.1.6: a local may shadow a function name
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int twice(int x) { return x * 2; }
+fn main() { int twice = 5; pn(twice); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_global.zc b/tests/conformance/4-statements/decl_shadow_global.zc
new file mode 100644
index 0000000..279c063
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_global.zc
@@ -0,0 +1,6 @@
+// expect: 2/1/
+// spec 4.1.6: a local may shadow a global
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g = 1;
+fn main() { int g = 2; pn(g); pn(1); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_outer_block.zc b/tests/conformance/4-statements/decl_shadow_outer_block.zc
new file mode 100644
index 0000000..eaf1fca
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_outer_block.zc
@@ -0,0 +1,10 @@
+// expect: 2/1/
+// spec 4.1.6: a local may shadow a local of an outer block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1;
+ { int a = 2; pn(a); }
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_shadow_param.zc b/tests/conformance/4-statements/decl_shadow_param.zc
new file mode 100644
index 0000000..9a91f1c
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_param.zc
@@ -0,0 +1,6 @@
+// expect: 9/5/
+// spec 4.1.6: a local may shadow a parameter
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int x) { { int x = 9; pn(x); } return x; }
+fn main() { pn(f(5)); return 0; }
diff --git a/tests/conformance/4-statements/decl_tag_only.zc b/tests/conformance/4-statements/decl_tag_only.zc
new file mode 100644
index 0000000..6bd731e
--- /dev/null
+++ b/tests/conformance/4-statements/decl_tag_only.zc
@@ -0,0 +1,10 @@
+// expect: 4/
+// spec 4.1.3: a declaration with only a tag declares an untyped local with that ownership tag
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ .m r = rt.new(2);
+ r[0] = 4;
+ pn(r[0]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_typed_array_declarator.zc b/tests/conformance/4-statements/decl_typed_array_declarator.zc
new file mode 100644
index 0000000..1b144aa
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_array_declarator.zc
@@ -0,0 +1,10 @@
+// expect: 10/
+// spec 4.1.1: a declarator followed by [n] makes an array of n
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a[10];
+ pn(sizeof(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_typed_multi.zc b/tests/conformance/4-statements/decl_typed_multi.zc
new file mode 100644
index 0000000..4dc4d1c
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_multi.zc
@@ -0,0 +1,11 @@
+// expect: 8/
+// spec 4.1.1: T a = e, b, c[10];
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1, b = 2, c[3];
+ c[2] = 5;
+ pn(a + b + c[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc b/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc
new file mode 100644
index 0000000..7bbf280
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc
@@ -0,0 +1,14 @@
+// expect: 3/
+// spec 4.1.1: T*.u declaration; spec 6.3.1 the tag is the initial state
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+.u make() {
+ int*.u p = rt.new(int);
+ *p = 3;
+ return u*p;
+}
+fn main() {
+ int* q = make();
+ pn(*q);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_uninit_global_is_zero.zc b/tests/conformance/4-statements/decl_uninit_global_is_zero.zc
new file mode 100644
index 0000000..6596d18
--- /dev/null
+++ b/tests/conformance/4-statements/decl_uninit_global_is_zero.zc
@@ -0,0 +1,8 @@
+// expect: 0/0/0/
+// spec 4.1.5 and 5.3.1: a global with no initializer is 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g;
+int[4] ga;
+fn main() { pn(g); pn(ga[0]); pn(ga[3]); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_void_variable.zc b/tests/conformance/4-statements/decl_void_variable.zc
new file mode 100644
index 0000000..c9a8d85
--- /dev/null
+++ b/tests/conformance/4-statements/decl_void_variable.zc
@@ -0,0 +1,5 @@
+// expect error: a variable can't be void
+// spec 4.1.7
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { void v = 0; return 0; }
diff --git a/tests/conformance/4-statements/do_basic.zc b/tests/conformance/4-statements/do_basic.zc
new file mode 100644
index 0000000..0194f93
--- /dev/null
+++ b/tests/conformance/4-statements/do_basic.zc
@@ -0,0 +1,11 @@
+// expect: 13/
+// spec 4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0, i = 0;
+ do { i++; if (i == 2) continue; n = n + i; } while (i < 5);
+ pn(n);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_break.zc b/tests/conformance/4-statements/do_break.zc
new file mode 100644
index 0000000..6f27c2e
--- /dev/null
+++ b/tests/conformance/4-statements/do_break.zc
@@ -0,0 +1,6 @@
+// expect: 3/
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; if (n == 3) break; } while (1); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_continue_jumps_to_test.zc b/tests/conformance/4-statements/do_continue_jumps_to_test.zc
new file mode 100644
index 0000000..0e5a7d1
--- /dev/null
+++ b/tests/conformance/4-statements/do_continue_jumps_to_test.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.5: continue jumps to the test (the test is false, so the loop ends)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; continue; n = 99; } while (0); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_runs_once.zc b/tests/conformance/4-statements/do_runs_once.zc
new file mode 100644
index 0000000..f320337
--- /dev/null
+++ b/tests/conformance/4-statements/do_runs_once.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.5: runs the body, then tests
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; } while (0); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/for_basic.zc b/tests/conformance/4-statements/for_basic.zc
new file mode 100644
index 0000000..97b9d1c
--- /dev/null
+++ b/tests/conformance/4-statements/for_basic.zc
@@ -0,0 +1,5 @@
+// expect: 10/
+// spec 4.6
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int s = 0; for (int i = 1; i <= 4; i++) s += i; pn(s); return 0; }
diff --git a/tests/conformance/4-statements/for_cond_tests_first.zc b/tests/conformance/4-statements/for_cond_tests_first.zc
new file mode 100644
index 0000000..6df4a4f
--- /dev/null
+++ b/tests/conformance/4-statements/for_cond_tests_first.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+// spec 4.6
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; for (int i = 5; i < 3; i++) n++; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/for_continue_runs_step.zc b/tests/conformance/4-statements/for_continue_runs_step.zc
new file mode 100644
index 0000000..371dc21
--- /dev/null
+++ b/tests/conformance/4-statements/for_continue_runs_step.zc
@@ -0,0 +1,10 @@
+// expect: 4/
+// spec 4.6 and 4.8.1: continue runs step then tests
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int c = 0;
+ for (int i = 0; i < 4; i++) { c++; continue; c = 99; }
+ pn(c);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/for_empty_parts.zc b/tests/conformance/4-statements/for_empty_parts.zc
new file mode 100644
index 0000000..7212ec6
--- /dev/null
+++ b/tests/conformance/4-statements/for_empty_parts.zc
@@ -0,0 +1,10 @@
+// expect: 3/
+// spec 4.6: init, cond and step may be empty; empty cond means true
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ for (;;) { i++; if (i == 3) break; }
+ pn(i);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/for_expression_init.zc b/tests/conformance/4-statements/for_expression_init.zc
new file mode 100644
index 0000000..3cf1093
--- /dev/null
+++ b/tests/conformance/4-statements/for_expression_init.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.6: init may be an expression
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i; int n = 0; for (i = 0; i < 3; i++) n++; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/for_let_init.zc b/tests/conformance/4-statements/for_let_init.zc
new file mode 100644
index 0000000..6041db1
--- /dev/null
+++ b/tests/conformance/4-statements/for_let_init.zc
@@ -0,0 +1,5 @@
+// expect: 6/
+// spec 4.6: init is a declaration (typed or let)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int s = 0; for (let i = 0; i < 4; i++) s += i; pn(s); return 0; }
diff --git a/tests/conformance/4-statements/for_variable_is_scoped.zc b/tests/conformance/4-statements/for_variable_is_scoped.zc
new file mode 100644
index 0000000..f154684
--- /dev/null
+++ b/tests/conformance/4-statements/for_variable_is_scoped.zc
@@ -0,0 +1,11 @@
+// expect: 100/5/
+// spec 4.6: the loop variable's scope is the loop (an outer i is untouched)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 100;
+ int last = 0;
+ for (int i = 0; i < 6; i++) last = i;
+ pn(i); pn(last);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/hints_forms_accepted.zc b/tests/conformance/4-statements/hints_forms_accepted.zc
new file mode 100644
index 0000000..a07ffd4
--- /dev/null
+++ b/tests/conformance/4-statements/hints_forms_accepted.zc
@@ -0,0 +1,9 @@
+// expect: 1/
+// spec 4.12: hints on, small, off have no effect on a normal run
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+hints on;
+hints small;
+hints off;
+fn main() { hints on; pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/if_basic.zc b/tests/conformance/4-statements/if_basic.zc
new file mode 100644
index 0000000..31cd9e1
--- /dev/null
+++ b/tests/conformance/4-statements/if_basic.zc
@@ -0,0 +1,10 @@
+// expect: 1/0/2/
+// spec 4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (5) pn(1); else pn(9);
+ if (0) pn(9); else pn(0);
+ if (-3) pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_branch_is_own_scope.zc b/tests/conformance/4-statements/if_branch_is_own_scope.zc
new file mode 100644
index 0000000..d4f82ea
--- /dev/null
+++ b/tests/conformance/4-statements/if_branch_is_own_scope.zc
@@ -0,0 +1,5 @@
+// expect error: q is used but never defined
+// spec 4.3: each branch is its own block even without braces
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { if (1) int q = 5; pn(q); return 0; }
diff --git a/tests/conformance/4-statements/if_else_binds_nearest.zc b/tests/conformance/4-statements/if_else_binds_nearest.zc
new file mode 100644
index 0000000..0c9f235
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_binds_nearest.zc
@@ -0,0 +1,8 @@
+// expect: 2/
+// spec 4.3: else binds to the nearest if
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (1) if (0) pn(1); else pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc b/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc
new file mode 100644
index 0000000..8549864
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc
@@ -0,0 +1,8 @@
+// expect:
+// spec 4.3: else binds to the nearest if, so nothing prints when the outer condition is false
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (0) if (0) pn(1); else pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_else_chain.zc b/tests/conformance/4-statements/if_else_chain.zc
new file mode 100644
index 0000000..292a3b0
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_chain.zc
@@ -0,0 +1,9 @@
+// expect: 3/
+// spec 4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 7;
+ if (n < 3) pn(1); else if (n < 6) pn(2); else if (n < 9) pn(3); else pn(4);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_float_condition.zc b/tests/conformance/4-statements/if_float_condition.zc
new file mode 100644
index 0000000..02a988c
--- /dev/null
+++ b/tests/conformance/4-statements/if_float_condition.zc
@@ -0,0 +1,11 @@
+// expect: 0/1/1/
+// spec 4.3: a float is false when +0.0 or -0.0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float z = 0.0, h = 0.5, n = 0.0 - 3.0;
+ if (z) pn(9); else pn(0);
+ if (h) pn(1); else pn(9);
+ if (n) pn(1); else pn(9);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/memdebug_double_free.zc b/tests/conformance/4-statements/memdebug_double_free.zc
new file mode 100644
index 0000000..ff91511
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_double_free.zc
@@ -0,0 +1,10 @@
+// expect error: zy: double free from line
+// spec 4.11
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_off.zc b/tests/conformance/4-statements/memdebug_off.zc
new file mode 100644
index 0000000..27de549
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_off.zc
@@ -0,0 +1,8 @@
+// expect: 1/
+// spec 4.11: memdebug off; stops the checks
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+memdebug off;
+fn main() { unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); } pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_report.zc b/tests/conformance/4-statements/memdebug_report.zc
new file mode 100644
index 0000000..db81c6d
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_report.zc
@@ -0,0 +1,15 @@
+// expect: 1/
+// spec 4.11: rt.memreport() returns the count of live recorded objects
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked {
+ int* q = rt.new(3);
+ int* r = rt.new(2);
+ rt.free(r);
+ pn(rt.memreport());
+ }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_report_line.zc b/tests/conformance/4-statements/memdebug_report_line.zc
new file mode 100644
index 0000000..8ab4273
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_report_line.zc
@@ -0,0 +1,15 @@
+// expect error: leak: line 8
+// spec 4.11: leak: line N W words per live recorded object (N is the allocation line)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked {
+ int* q = rt.new(3);
+ int* r = rt.new(2);
+ rt.free(q);
+ rt.memreport();
+ }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_scrub_accepted.zc b/tests/conformance/4-statements/memdebug_scrub_accepted.zc
new file mode 100644
index 0000000..5253918
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_scrub_accepted.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+// spec 4.11: memdebug scrub; is a form of the statement
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug scrub;
+fn main() { pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_scrub_fills.zc b/tests/conformance/4-statements/memdebug_scrub_fills.zc
new file mode 100644
index 0000000..ad15e3d
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_scrub_fills.zc
@@ -0,0 +1,10 @@
+// expect: 57005/
+// spec 4.11: memdebug scrub; fills freed payloads with 57005
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug scrub;
+fn main() {
+ unchecked { int* p = rt.new(int); *p = 5; rt.free(p); pn(*p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_statement_form.zc b/tests/conformance/4-statements/memdebug_statement_form.zc
new file mode 100644
index 0000000..e9273b1
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_statement_form.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.11: memdebug is also a statement in a function
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { memdebug on; int* p = rt.new(int); rt.free(p); pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_use_after_free.zc b/tests/conformance/4-statements/memdebug_use_after_free.zc
new file mode 100644
index 0000000..434aa5a
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_use_after_free.zc
@@ -0,0 +1,10 @@
+// expect error: zy: use after free from line
+// spec 4.11
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked { int* p = rt.new(int); *p = 5; rt.free(p); pn(*p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/nested_return_in_loop.zc b/tests/conformance/4-statements/nested_return_in_loop.zc
new file mode 100644
index 0000000..ba246fb
--- /dev/null
+++ b/tests/conformance/4-statements/nested_return_in_loop.zc
@@ -0,0 +1,9 @@
+// expect: 3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int find(int want) {
+ for (int i = 0; i < 10; i++) { if (i == want) return i; }
+ return -1;
+}
+fn main() { pn(find(3)); return 0; }
+
diff --git a/tests/conformance/4-statements/o3_asm_cannot_reach.zc b/tests/conformance/4-statements/o3_asm_cannot_reach.zc
new file mode 100644
index 0000000..4150742
--- /dev/null
+++ b/tests/conformance/4-statements/o3_asm_cannot_reach.zc
@@ -0,0 +1,6 @@
+// expect error: asm can't reach an o3 variable
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int x = 1; asm { x @ } } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_block.zc b/tests/conformance/4-statements/o3_block.zc
new file mode 100644
index 0000000..3291152
--- /dev/null
+++ b/tests/conformance/4-statements/o3_block.zc
@@ -0,0 +1,11 @@
+// expect: 45/
+// spec 4.10.1: o3 { } marks a block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int t = 0;
+ o3 { int s = 0; for (int i = 0; i < 10; i++) s += i; t = s; }
+ pn(t);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_fn_form.zc b/tests/conformance/4-statements/o3_fn_form.zc
new file mode 100644
index 0000000..30cfc6b
--- /dev/null
+++ b/tests/conformance/4-statements/o3_fn_form.zc
@@ -0,0 +1,7 @@
+// expect: 6/
+// spec 4.10.1: o3 fn f(...)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 fn triple(int a) { return a * 3; }
+fn main() { pn(triple(2)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_function_sum.zc b/tests/conformance/4-statements/o3_function_sum.zc
new file mode 100644
index 0000000..37b3ef4
--- /dev/null
+++ b/tests/conformance/4-statements/o3_function_sum.zc
@@ -0,0 +1,13 @@
+// expect: 10/
+// spec 4.10.1 example: o3 changes speed, not meaning
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 int sum(fixed int[?] a) { int s = 0; for (int i = 0; i < len(a); i++) s += a[i]; return s; }
+fn main() {
+ fixed int[?] a = rt.new(fixed int[?], 4);
+ for (int i = 0; i < 4; i++) a[i] = i + 1;
+ pn(sum(a));
+ rt.free(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc b/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc
new file mode 100644
index 0000000..4d2306d
--- /dev/null
+++ b/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc
@@ -0,0 +1,6 @@
+// expect: 2/
+// spec 4.10.2: a nested o3 is an ordinary block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int a = 1; o3 { int b = a + 1; pn(b); } } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_no_address_of.zc b/tests/conformance/4-statements/o3_no_address_of.zc
new file mode 100644
index 0000000..47cad16
--- /dev/null
+++ b/tests/conformance/4-statements/o3_no_address_of.zc
@@ -0,0 +1,6 @@
+// expect error: an o3 variable has no address
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int x = 1; int* p = &x; } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc b/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc
new file mode 100644
index 0000000..7fe3f09
--- /dev/null
+++ b/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+// spec 4.10.2: an o3 { } outside a function is an ordinary block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 { }
+fn main() { pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_parameter_needs_type.zc b/tests/conformance/4-statements/o3_parameter_needs_type.zc
new file mode 100644
index 0000000..37384be
--- /dev/null
+++ b/tests/conformance/4-statements/o3_parameter_needs_type.zc
@@ -0,0 +1,7 @@
+// expect error: o3 parameters need a type
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 fn f(a) { return a; }
+fn main() { return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_single_variable.zc b/tests/conformance/4-statements/o3_single_variable.zc
new file mode 100644
index 0000000..3deca8d
--- /dev/null
+++ b/tests/conformance/4-statements/o3_single_variable.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+// spec 4.10.1: o3 T x = e; marks one variable
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 int x = 7; pn(x); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_variable_needs_type.zc b/tests/conformance/4-statements/o3_variable_needs_type.zc
new file mode 100644
index 0000000..0741302
--- /dev/null
+++ b/tests/conformance/4-statements/o3_variable_needs_type.zc
@@ -0,0 +1,6 @@
+// expect error: o3 variables need a type
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { let x = 1; pn(x); } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/return_bare_is_zero.zc b/tests/conformance/4-statements/return_bare_is_zero.zc
new file mode 100644
index 0000000..deb9235
--- /dev/null
+++ b/tests/conformance/4-statements/return_bare_is_zero.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+// spec 4.8.2: return; returns 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { return; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_fall_off_is_zero.zc b/tests/conformance/4-statements/return_fall_off_is_zero.zc
new file mode 100644
index 0000000..e0d1229
--- /dev/null
+++ b/tests/conformance/4-statements/return_fall_off_is_zero.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+// spec 4.8.2: falling off the end returns 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { int a = 1; a++; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_frees_owned_locals.zc b/tests/conformance/4-statements/return_frees_owned_locals.zc
new file mode 100644
index 0000000..ccff11c
--- /dev/null
+++ b/tests/conformance/4-statements/return_frees_owned_locals.zc
@@ -0,0 +1,11 @@
+// expect: 5/
+// spec 4.8.2 and 6.5.1: return frees every owned local of the scopes it leaves
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int n) {
+ int* p = rt.new(int);
+ *p = n;
+ if (n > 1) return *p;
+ return 0;
+}
+fn main() { pn(f(5)); return 0; }
diff --git a/tests/conformance/4-statements/return_outside_function.zc b/tests/conformance/4-statements/return_outside_function.zc
new file mode 100644
index 0000000..82e8f35
--- /dev/null
+++ b/tests/conformance/4-statements/return_outside_function.zc
@@ -0,0 +1,6 @@
+// expect error: zc: line 5:
+// spec 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+return 1;
+fn main() { return 0; }
diff --git a/tests/conformance/4-statements/return_value_converted_float.zc b/tests/conformance/4-statements/return_value_converted_float.zc
new file mode 100644
index 0000000..43248e1
--- /dev/null
+++ b/tests/conformance/4-statements/return_value_converted_float.zc
@@ -0,0 +1,7 @@
+// expect: 2.000000/
+// spec 4.8.2: converted to the result type
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+float g() { return 2; }
+fn main() { pf(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_value_converted_int.zc b/tests/conformance/4-statements/return_value_converted_int.zc
new file mode 100644
index 0000000..346c67b
--- /dev/null
+++ b/tests/conformance/4-statements/return_value_converted_int.zc
@@ -0,0 +1,6 @@
+// expect: -2/
+// spec 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { return -2.7; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_void_value_typecheck_on.zc b/tests/conformance/4-statements/return_void_value_typecheck_on.zc
new file mode 100644
index 0000000..a1d35ef
--- /dev/null
+++ b/tests/conformance/4-statements/return_void_value_typecheck_on.zc
@@ -0,0 +1,7 @@
+// expect error: type error: return value: expected void, got int
+// spec 4.8.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+typecheck on;
+void f() { return 4; }
+fn main() { f(); return 0; }
diff --git a/tests/conformance/4-statements/stmt_block_scope.zc b/tests/conformance/4-statements/stmt_block_scope.zc
new file mode 100644
index 0000000..3b6fd6e
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_block_scope.zc
@@ -0,0 +1,5 @@
+// expect: 3/1/
+// spec 4.2: { ... } is a block with its own scope
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; { int a = 3; pn(a); } pn(a); return 0; }
diff --git a/tests/conformance/4-statements/stmt_empty_statement.zc b/tests/conformance/4-statements/stmt_empty_statement.zc
new file mode 100644
index 0000000..520a451
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_empty_statement.zc
@@ -0,0 +1,5 @@
+// expect: 1/
+// spec 4.2: ; alone is empty
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { ;;; pn(1); ; return 0; }
diff --git a/tests/conformance/4-statements/stmt_expression_value_dropped.zc b/tests/conformance/4-statements/stmt_expression_value_dropped.zc
new file mode 100644
index 0000000..b69ccaf
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_expression_value_dropped.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+// spec 4.2: the value of an expression statement is dropped
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; a + 5; a = a + 1; 7; pn(a); return 0; }
diff --git a/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc b/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc
new file mode 100644
index 0000000..999f8c0
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc
@@ -0,0 +1,5 @@
+// expect error: a new object (or a u result) can't be thrown away
+// spec 4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { rt.new(int); return 0; }
diff --git a/tests/conformance/4-statements/stmt_u_result_thrown_away.zc b/tests/conformance/4-statements/stmt_u_result_thrown_away.zc
new file mode 100644
index 0000000..834dd96
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_u_result_thrown_away.zc
@@ -0,0 +1,6 @@
+// expect error: a new object (or a u result) can't be thrown away
+// spec 4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int*.u mk() { int*.u p = rt.new(int); return u*p; }
+fn main() { mk(); return 0; }
diff --git a/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc b/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc
new file mode 100644
index 0000000..d69b64a
--- /dev/null
+++ b/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc
@@ -0,0 +1,13 @@
+// expect: 3/
+// spec 4.7.1: break in a switch inside a loop leaves the switch, not the loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0;
+ for (int i = 0; i < 3; i++) {
+ switch (i) { case 1: break; default: n++; }
+ n++;
+ }
+ pn(n);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_break_leaves_early.zc b/tests/conformance/4-statements/switch_break_leaves_early.zc
new file mode 100644
index 0000000..8adbe64
--- /dev/null
+++ b/tests/conformance/4-statements/switch_break_leaves_early.zc
@@ -0,0 +1,10 @@
+// expect: 1/9/
+// spec 4.7.1: break inside a switch leaves it early
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int k = 1;
+ switch (k) { case 1: pn(1); break; pn(2); }
+ pn(9);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_case_own_block.zc b/tests/conformance/4-statements/switch_case_own_block.zc
new file mode 100644
index 0000000..16bc31f
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_own_block.zc
@@ -0,0 +1,11 @@
+// expect: 5/6/
+// spec 4.7.2: the statements of a case form their own block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void t(int k) {
+ switch (k) {
+ case 1: int x = 5; pn(x);
+ case 2: int x = 6; pn(x);
+ }
+}
+fn main() { t(1); t(2); return 0; }
diff --git a/tests/conformance/4-statements/switch_case_three.zc b/tests/conformance/4-statements/switch_case_three.zc
new file mode 100644
index 0000000..eefaced
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_three.zc
@@ -0,0 +1,10 @@
+// expect: three/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 3;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_case_underscore.zc b/tests/conformance/4-statements/switch_case_underscore.zc
new file mode 100644
index 0000000..4d05f8e
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_underscore.zc
@@ -0,0 +1,7 @@
+// expect: d/one/
+// spec 4.7.1: case _ is a catch-all with the same meaning as default
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+void t(int k) { switch (k) { case 1: ps("one"); case _: ps("d"); } }
+fn main() { t(8); t(1); return 0; }
diff --git a/tests/conformance/4-statements/switch_continue_continues_loop.zc b/tests/conformance/4-statements/switch_continue_continues_loop.zc
new file mode 100644
index 0000000..d408253
--- /dev/null
+++ b/tests/conformance/4-statements/switch_continue_continues_loop.zc
@@ -0,0 +1,10 @@
+// expect: 1/3/4/
+// spec 4.7.1: continue inside a switch continues the enclosing loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ for (int i = 1; i <= 4; i++) {
+ switch (i) { case 2: continue; default: pn(i); }
+ }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_and_underscore.zc b/tests/conformance/4-statements/switch_default_and_underscore.zc
new file mode 100644
index 0000000..92c9025
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_and_underscore.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one
+// spec 4.7.1: default and _ are the same thing, so a switch can have only one of them
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { default: pn(1); case _: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/switch_default_first_position_not_matched.zc b/tests/conformance/4-statements/switch_default_first_position_not_matched.zc
new file mode 100644
index 0000000..4d63ae3
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_first_position_not_matched.zc
@@ -0,0 +1,10 @@
+// expect: one/
+// spec 4.7.1: default runs when no label matches, wherever it is written
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 1;
+ switch (k) { default: ps("d"); case 1: ps("one"); case 2: ps("two"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_first_position_taken.zc b/tests/conformance/4-statements/switch_default_first_position_taken.zc
new file mode 100644
index 0000000..113795f
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_first_position_taken.zc
@@ -0,0 +1,10 @@
+// expect: d/
+// spec 4.7.1: default runs when no label matches, wherever it is written
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 7;
+ switch (k) { default: ps("d"); case 1: ps("one"); case 2: ps("two"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_middle.zc b/tests/conformance/4-statements/switch_default_middle.zc
new file mode 100644
index 0000000..a390efe
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_middle.zc
@@ -0,0 +1,7 @@
+// expect: d/two/
+// spec 4.7.1: default in the middle
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+void t(int k) { switch (k) { case 1: ps("one"); default: ps("d"); case 2: ps("two"); } }
+fn main() { t(5); t(2); return 0; }
diff --git a/tests/conformance/4-statements/switch_default_runs.zc b/tests/conformance/4-statements/switch_default_runs.zc
new file mode 100644
index 0000000..bc42976
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_runs.zc
@@ -0,0 +1,10 @@
+// expect: d/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 9;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc b/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc
new file mode 100644
index 0000000..e2a2e3b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc
@@ -0,0 +1,10 @@
+// expect: first/
+// spec 4.7.2: duplicate labels are not an error, the first matching case in source order runs
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 4;
+ switch (k) { case 4: ps("first"); case 4: ps("second"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_expression_evaluated_once.zc b/tests/conformance/4-statements/switch_expression_evaluated_once.zc
new file mode 100644
index 0000000..bf82b99
--- /dev/null
+++ b/tests/conformance/4-statements/switch_expression_evaluated_once.zc
@@ -0,0 +1,10 @@
+// expect: 1/hit/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ switch (i++) { case 5: pn(5); case 6: pn(6); case 0: rt.put_s("hit"); }
+ pn(i);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_label_forms.zc b/tests/conformance/4-statements/switch_label_forms.zc
new file mode 100644
index 0000000..ae131aa
--- /dev/null
+++ b/tests/conformance/4-statements/switch_label_forms.zc
@@ -0,0 +1,16 @@
+// expect: neg/chr/sum/enum/
+// spec 4.7.1 and 3.14: labels are constant expressions
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum color { RED, GREEN };
+void t(int k) {
+ switch (k) {
+ case -1: rt.put_s("neg");
+ case 'a': rt.put_s("chr");
+ case 1 + 1 * 3: rt.put_s("sum");
+ case color.GREEN: rt.put_s("enum");
+ }
+ rt.put_c(10);
+}
+fn main() { t(-1); pn(0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/switch_nested.zc b/tests/conformance/4-statements/switch_nested.zc
new file mode 100644
index 0000000..7fd9a34
--- /dev/null
+++ b/tests/conformance/4-statements/switch_nested.zc
@@ -0,0 +1,14 @@
+// expect: in2/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int a = 1, b = 2;
+ switch (a) {
+ case 1:
+ switch (b) { case 1: ps("in1"); break; case 2: ps("in2"); break; }
+ case 2: ps("outer2");
+ }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_no_fallthrough_k2.zc b/tests/conformance/4-statements/switch_no_fallthrough_k2.zc
new file mode 100644
index 0000000..276ca30
--- /dev/null
+++ b/tests/conformance/4-statements/switch_no_fallthrough_k2.zc
@@ -0,0 +1,10 @@
+// expect: one-two/
+// spec 4.7.1: cases do not fall through
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 2;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_no_match_no_default.zc b/tests/conformance/4-statements/switch_no_match_no_default.zc
new file mode 100644
index 0000000..3021388
--- /dev/null
+++ b/tests/conformance/4-statements/switch_no_match_no_default.zc
@@ -0,0 +1,11 @@
+// expect: after/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 5;
+ switch (k) { case 1: ps("one"); case 2: ps("two"); }
+ ps("after");
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_non_constant_label.zc b/tests/conformance/4-statements/switch_non_constant_label.zc
new file mode 100644
index 0000000..dc42b5b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_non_constant_label.zc
@@ -0,0 +1,5 @@
+// expect error: expected a constant
+// spec 4.7.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1, j = 2; switch (k) { case j: pn(1); } return 0; }
diff --git a/tests/conformance/4-statements/switch_return_inside_case.zc b/tests/conformance/4-statements/switch_return_inside_case.zc
new file mode 100644
index 0000000..7375e79
--- /dev/null
+++ b/tests/conformance/4-statements/switch_return_inside_case.zc
@@ -0,0 +1,6 @@
+// expect: 20/10/
+// spec 4.7.1 and 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int k) { switch (k) { case 1: return 10; case 2: return 20; } return 0; }
+fn main() { pn(f(2)); pn(f(1)); return 0; }
diff --git a/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc b/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc
new file mode 100644
index 0000000..45a9846
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc
@@ -0,0 +1,11 @@
+// expect: 2/
+// spec 4.7.3: no warning when every member is covered
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum e { a { int v; }, b };
+fn main() {
+ e* s = e.a(2);
+ switch (s) { case a(v): pn(v); case b: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_binding_count.zc b/tests/conformance/4-statements/switch_tagged_binding_count.zc
new file mode 100644
index 0000000..08006a6
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_binding_count.zc
@@ -0,0 +1,11 @@
+// expect error: a case binds every field of its member
+// spec 4.7.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(1, 2);
+ switch (s) { case rect(w): pn(w); default: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc b/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc
new file mode 100644
index 0000000..ed8ee03
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc
@@ -0,0 +1,12 @@
+// expect error: w is used but never defined
+// spec 4.7.3: each payload field is bound to a new local scoped to that case
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(1, 2);
+ switch (s) { case rect(w, h): pn(w); default: pn(0); }
+ pn(w);
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_circle.zc b/tests/conformance/4-statements/switch_tagged_circle.zc
new file mode 100644
index 0000000..b1b1c55
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_circle.zc
@@ -0,0 +1,11 @@
+// expect: 7/
+// spec 4.7.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(7);
+ switch (s) { case circle(r): pn(r); case rect(w, h): pn(w * h); case dot: rt.put_s("dot"); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_default_no_warning.zc b/tests/conformance/4-statements/switch_tagged_default_no_warning.zc
new file mode 100644
index 0000000..0a22a7a
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_default_no_warning.zc
@@ -0,0 +1,11 @@
+// expect: 1/
+// spec 4.7.3: no warning when there is a default
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); default: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_example.zc b/tests/conformance/4-statements/switch_tagged_example.zc
new file mode 100644
index 0000000..932aefc
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_example.zc
@@ -0,0 +1,11 @@
+// expect: 20/
+// spec 4.7.3 example: prints 20
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(4, 5);
+ switch (s) { case circle(r): pn(r); case rect(w, h): pn(w * h); case dot: rt.put_s("dot"); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_match_by_tag.zc b/tests/conformance/4-statements/switch_tagged_match_by_tag.zc
new file mode 100644
index 0000000..9d2f7a1
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_match_by_tag.zc
@@ -0,0 +1,19 @@
+// expect: dot/dot2/
+// spec 4.7.3: case member: or case member(): matches by tag
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+void t(shape* s) {
+ switch (s) { case circle: rt.put_s("circle"); case rect(): rt.put_s("rect"); case dot: rt.put_s("dot"); }
+ rt.put_c(10);
+}
+void u(shape* s) {
+ switch (s) { case circle: rt.put_s("circle"); case rect: rt.put_s("rect"); case dot(): rt.put_s("dot2"); }
+ rt.put_c(10);
+}
+fn main() {
+ shape* a = shape.dot();
+ t(a); u(a);
+ rt.free(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc b/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc
new file mode 100644
index 0000000..d567da5
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc
@@ -0,0 +1,11 @@
+// expect error: warning: this switch doesn't cover rect, dot
+// spec 4.7.3: a switch on a tagged enum with no default that omits a member prints a warning
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc b/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc
new file mode 100644
index 0000000..dfacc9c
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc
@@ -0,0 +1,11 @@
+// expect: zc: line 8: warning: this switch doesn't cover rect, dot/1/
+// spec 4.7.3 and 6.14: the warning is not an error, the program runs
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_two_defaults.zc b/tests/conformance/4-statements/switch_two_defaults.zc
new file mode 100644
index 0000000..e1f4f90
--- /dev/null
+++ b/tests/conformance/4-statements/switch_two_defaults.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one default
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { default: pn(1); default: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/switch_two_underscores.zc b/tests/conformance/4-statements/switch_two_underscores.zc
new file mode 100644
index 0000000..afc5f2b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_two_underscores.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one catch-all case
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { case _: pn(1); case _: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/unchecked_fn.zc b/tests/conformance/4-statements/unchecked_fn.zc
new file mode 100644
index 0000000..fa2055e
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_fn.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.9: unchecked fn makes one function unchecked
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked fn leaky() { int* p = rt.new(int); return 0; }
+fn main() { leaky(); pn(1); return 0; }
diff --git a/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc b/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc
new file mode 100644
index 0000000..e93a582
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc
@@ -0,0 +1,6 @@
+// expect error: q: owned object is never used
+// spec 4.9: only that function is unchecked
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked fn leaky() { int* p = rt.new(int); return 0; }
+fn main() { int* q = rt.new(int); leaky(); return 0; }
diff --git a/tests/conformance/4-statements/unchecked_stmt_block.zc b/tests/conformance/4-statements/unchecked_stmt_block.zc
new file mode 100644
index 0000000..eca1a38
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_stmt_block.zc
@@ -0,0 +1,9 @@
+// expect: ok/
+// spec 4.9 and 8.3: in unchecked code a second free of an object is ignored
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); }
+ rt.put_s("ok"); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_stmt_single.zc b/tests/conformance/4-statements/unchecked_stmt_single.zc
new file mode 100644
index 0000000..2bdccb1
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_stmt_single.zc
@@ -0,0 +1,10 @@
+// expect: 3/
+// spec 4.9: unchecked stmt
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1;
+ unchecked a = a + 2;
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc b/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc
new file mode 100644
index 0000000..439eca7
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc
@@ -0,0 +1,10 @@
+// expect: 1/
+// spec 4.9: unchecked; at top level switches the analyzer off for the rest of the unit
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked;
+fn main() {
+ int* p = rt.new(int);
+ pn(1);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc b/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc
new file mode 100644
index 0000000..a5f0d6d
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc
@@ -0,0 +1,9 @@
+// expect error: p: is tracked by the analyzer and can't be used in unchecked code
+// spec 4.9
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = rt.new(int);
+ unchecked { *p = 2; }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/while_basic.zc b/tests/conformance/4-statements/while_basic.zc
new file mode 100644
index 0000000..05fa171
--- /dev/null
+++ b/tests/conformance/4-statements/while_basic.zc
@@ -0,0 +1,5 @@
+// expect: 10/
+// spec 4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 0, s = 0; while (i < 5) { i++; s += i; } pn(s - 5); return 0; }
diff --git a/tests/conformance/4-statements/while_continue.zc b/tests/conformance/4-statements/while_continue.zc
new file mode 100644
index 0000000..28c32b0
--- /dev/null
+++ b/tests/conformance/4-statements/while_continue.zc
@@ -0,0 +1,10 @@
+// expect: 25/
+// spec 4.8.1: continue goes to the next iteration of a while (the test)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0, s = 0;
+ while (i < 10) { i++; if (i % 2 == 0) continue; s += i; }
+ pn(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/while_one_exit_by_return.zc b/tests/conformance/4-statements/while_one_exit_by_return.zc
new file mode 100644
index 0000000..6e71d2f
--- /dev/null
+++ b/tests/conformance/4-statements/while_one_exit_by_return.zc
@@ -0,0 +1,6 @@
+// expect: 4/
+// spec 4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f() { int i = 0; while (1) { i++; if (i == 4) return i; } }
+fn main() { pn(f()); return 0; }
diff --git a/tests/conformance/4-statements/while_one_exits_by_break.zc b/tests/conformance/4-statements/while_one_exits_by_break.zc
new file mode 100644
index 0000000..e105204
--- /dev/null
+++ b/tests/conformance/4-statements/while_one_exits_by_break.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.4: while (1) exits by break or return
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 0; while (1) { i++; if (i == 3) break; } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/while_tests_before.zc b/tests/conformance/4-statements/while_tests_before.zc
new file mode 100644
index 0000000..069afbf
--- /dev/null
+++ b/tests/conformance/4-statements/while_tests_before.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+// spec 4.4: tests before each pass
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; while (0) n++; pn(n); return 0; }