Skip to content

Lower a fall-through-free switch as a chain of conditionals - #234

Draft
nikswamy wants to merge 2 commits into
mainfrom
nswamy/pal-pr20-switch-default-and-if-chain
Draft

Lower a fall-through-free switch as a chain of conditionals#234
nikswamy wants to merge 2 commits into
mainfrom
nswamy/pal-pr20-switch-default-and-if-chain

Conversation

@nikswamy

Copy link
Copy Markdown
Contributor

Part of the upstreaming of nswamy/pal-c-project-integration (PR20 of 35 PRs) — see PR_PLAN.md on that branch for the whole plan and the dependency graph.

Base: main. Depends on nothing; reviewable on its own.

Consecutive labels nest in clang, so case 2: case 3: default: arrives as
CaseStmt(2, CaseStmt(3, DefaultStmt(..))); the group builder peeled only the CaseStmt
chain and statement translation then rejected the stray DefaultStmt. Peels the whole
chain in either order and marks the group default, dropping its explicit case values —
an arm reached by anything gains nothing from also testing for 2 or 3. The second commit
lowers a fall-through-free switch with a default as an if/else chain: the general
encoding threads hit/brk flags, so every arm executes under a compound condition over
mutable state, and the join — phrased in terms of the scrutinee — never meets the guards.
An explicit switch postcondition still takes the match form, which needs one.

Commits

  • Recognize a default that shares an arm with explicit cases
  • Lower a fall-through-free switch as a chain of conditionals

Testing

Verified: make rust lib, test/check-template.sh, cargo fmt --check, clang-format --dry-run --Werror, and F* verification of test/switch_stmt.

nikswamy and others added 2 commits August 18, 2026 15:27
Consecutive labels nest in clang: `case 2: case 3: default: r = 30;`
arrives as CaseStmt(2, CaseStmt(3, DefaultStmt(r = 30))), not as three
siblings. The group builder peeled only the CaseStmt chain, so the
DefaultStmt was pushed into the arm's body, where statement translation
rejected it as unsupported.

Peel the whole label chain, in either order, and mark the group default.
Its explicit case values are then dropped, because an arm reached by
anything gains nothing from also testing for 2 or 3, and emitting the
test would leave a redundant condition in the generated Pulse.

Both emitters already keyed off the group's default flag, so the
terminal-break match encoding and the general fall-through encoding both
follow. The regression covers a default written after the cases it
shares an arm with, the same without a terminal break, one written
before them, and the annotated form that reaches the match encoding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 981f7d3c-6a91-47ad-84d7-7aadf747123d
(cherry picked from commit 12f46ba)
The general switch encoding threads `hit` and `brk` flags to model
fall-through, so every arm executes under `!brk && (hit || scrut == v)`
-- a compound condition over mutable state. When the arms differ in what
they own, which is the shape of any dispatch that writes an output, the
join is phrased in terms of the scrutinee while the guards are phrased
in terms of the flags, and the two never meet. Binding a guard to a
`let` fixes the first test but not the chained one, because `brk`
becomes `match cond_a with true -> true | false -> false`.

A switch with no fall-through and a `default` is an if/else chain, so
say so: test the scrutinee directly and each branch condition is the one
the join is phrased in. The emitted Pulse is legible besides. An
explicit switch postcondition still takes the existing match form, which
needs one -- Pulse cannot infer a postcondition for a non-tail
conditional.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 981f7d3c-6a91-47ad-84d7-7aadf747123d
(cherry picked from commit 59600ae)
@gebner

gebner commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

!diff

@github-actions

Copy link
Copy Markdown

Generated F* output diff

Effect of this pull request on the F* code pal generates for the test suite (f9d4dd2d3123dc).

Summary
 {base => head}/switch_stmt/Func_accumulate_with_fallthrough.fst       | 24 ++++++++++++------------
 {base => head}/switch_stmt/Func_call_in_case.fst                      |  6 +++---
 {base => head}/switch_stmt/Func_classify.fst                          | 29 ++++++++---------------------
 {base => head}/switch_stmt/Func_classify_with_returns.fst             | 18 +++++++++---------
 {base => head}/switch_stmt/Func_day_type.fst                          | 27 ++++++++-------------------
 /dev/null => head/switch_stmt/Func_default_after_cases.fst            | 32 ++++++++++++++++++++++++++++++++
 /dev/null => head/switch_stmt/Func_default_after_cases.fsti           | 16 ++++++++++++++++
 /dev/null => head/switch_stmt/Func_default_after_cases_annotated.fst  | 31 +++++++++++++++++++++++++++++++
 /dev/null => head/switch_stmt/Func_default_after_cases_annotated.fsti | 11 +++++++++++
 /dev/null => head/switch_stmt/Func_default_after_cases_no_break.fst   | 34 ++++++++++++++++++++++++++++++++++
 /dev/null => head/switch_stmt/Func_default_after_cases_no_break.fsti  | 12 ++++++++++++
 /dev/null => head/switch_stmt/Func_default_before_cases.fst           | 25 +++++++++++++++++++++++++
 /dev/null => head/switch_stmt/Func_default_before_cases.fsti          | 12 ++++++++++++
 {base => head}/switch_stmt/Func_sparse_string_name.fst                | 36 ++++++++++++++++++------------------
 {base => head}/switch_stmt/Func_sparse_unsorted.fst                   | 36 ++++++++++++++++++------------------
 {base => head}/switch_stmt/Func_terminal_break_i32.fst                |  6 +++---
 {base => head}/switch_stmt/Func_terminal_break_i64.fst                |  6 +++---
 {base => head}/switch_stmt/Func_terminal_break_promoted_u8.fst        |  6 +++---
 {base => head}/switch_stmt/Func_terminal_break_scale.fst              | 38 +++++++++++++++++++-------------------
 {base => head}/switch_stmt/Func_terminal_break_u32.fst                |  6 +++---
 {base => head}/switch_stmt/Func_terminal_break_u64.fst                |  6 +++---
 21 files changed, 283 insertions(+), 134 deletions(-)

Full diff: full diff artifact

Diff
diff --git base/switch_stmt/Func_accumulate_with_fallthrough.fst head/switch_stmt/Func_accumulate_with_fallthrough.fst
index 383d025..704317b 100644
--- base/switch_stmt/Func_accumulate_with_fallthrough.fst
+++ head/switch_stmt/Func_accumulate_with_fallthrough.fst
@@ -15,21 +15,21 @@ divergent fn func_accumulate_with_fallthrough (var_x: Typedef_int32_t.ty_int32_t
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_2 : Typedef_int32_t.ty_int32_t = (!var_x);
-  let mut var___switch_hit_2 : bool;
-  var___switch_hit_2 := false;
-  let mut var___switch_brk_2 : bool;
-  var___switch_brk_2 := false;
-  if (((not (!var___switch_brk_2)) &&
-        ((!var___switch_hit_2) || (false || (var___switch_scrut_2 = 0l))))) {
-    var___switch_hit_2 := true;
+  let var___switch_scrut_6 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let mut var___switch_hit_6 : bool;
+  var___switch_hit_6 := false;
+  let mut var___switch_brk_6 : bool;
+  var___switch_brk_6 := false;
+  if (((not (!var___switch_brk_6)) &&
+        ((!var___switch_hit_6) || (false || (var___switch_scrut_6 = 0l))))) {
+    var___switch_hit_6 := true;
     var_result := 10l;
   } else {};
-  if (((not (!var___switch_brk_2)) &&
-        ((!var___switch_hit_2) || (false || (var___switch_scrut_2 = 1l))))) {
-    var___switch_hit_2 := true;
+  if (((not (!var___switch_brk_6)) &&
+        ((!var___switch_hit_6) || (false || (var___switch_scrut_6 = 1l))))) {
+    var___switch_hit_6 := true;
     var_result := ((!var_result) `Int32.add` 1l);
-    var___switch_brk_2 := true;
+    var___switch_brk_6 := true;
   } else {};
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_call_in_case.fst head/switch_stmt/Func_call_in_case.fst
index 45bbb9a..1e9c82a 100644
--- base/switch_stmt/Func_call_in_case.fst
+++ head/switch_stmt/Func_call_in_case.fst
@@ -12,9 +12,9 @@ divergent fn func_call_in_case (var_x: Typedef_int32_t.ty_int32_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_3 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let var___switch_scrut_7 : Typedef_int32_t.ty_int32_t = (!var_x);
   {
-    match (var___switch_scrut_3) {
+    match (var___switch_scrut_7) {
         0l -> {
           var_result := 1l;
         }
@@ -24,6 +24,6 @@ divergent fn func_call_in_case (var_x: Typedef_int32_t.ty_int32_t)
     };
   }
   ensures ((live var_x) ** (live var_result))
-  label __pal_match_join_0:;
+  label __pal_match_join_1:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_classify.fst head/switch_stmt/Func_classify.fst
index 8d12994..a947174 100644
--- base/switch_stmt/Func_classify.fst
+++ head/switch_stmt/Func_classify.fst
@@ -20,27 +20,14 @@ divergent fn func_classify (var_x: Typedef_int32_t.ty_int32_t)
   let mut var_r : Typedef_int32_t.ty_int32_t;
   var_r := 0l;
   let var___switch_scrut_1 : Typedef_int32_t.ty_int32_t = (!var_x);
-  let mut var___switch_hit_1 : bool;
-  var___switch_hit_1 := false;
-  let mut var___switch_brk_1 : bool;
-  var___switch_brk_1 := false;
-  if (((not (!var___switch_brk_1)) &&
-        ((!var___switch_hit_1) || (false || (var___switch_scrut_1 = 0l))))) {
-    var___switch_hit_1 := true;
+  if ((var___switch_scrut_1 = 0l)) {
     var_r := 10l;
-    var___switch_brk_1 := true;
-  } else {};
-  if (((not (!var___switch_brk_1)) &&
-        ((!var___switch_hit_1) ||
-          ((false || (var___switch_scrut_1 = 1l)) || (var___switch_scrut_1 = 2l))))) {
-    var___switch_hit_1 := true;
-    var_r := 20l;
-    var___switch_brk_1 := true;
-  } else {};
-  if ((not (!var___switch_brk_1))) {
-    var___switch_hit_1 := true;
-    var_r := 30l;
-    var___switch_brk_1 := true;
-  } else {};
+  } else {
+    if (((var___switch_scrut_1 = 1l) || (var___switch_scrut_1 = 2l))) {
+      var_r := 20l;
+    } else {
+      var_r := 30l;
+    };
+  };
   return (!var_r);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_classify_with_returns.fst head/switch_stmt/Func_classify_with_returns.fst
index 3b1567d..dbeccba 100644
--- base/switch_stmt/Func_classify_with_returns.fst
+++ head/switch_stmt/Func_classify_with_returns.fst
@@ -10,16 +10,16 @@ divergent fn func_classify_with_returns (var_x: Typedef_int32_t.ty_int32_t)
   ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
 {
   let mut var_x = var_x;
-  let var___switch_scrut_4 : Typedef_int32_t.ty_int32_t = (!var_x);
-  let mut var___switch_hit_4 : bool;
-  var___switch_hit_4 := false;
-  let mut var___switch_brk_4 : bool;
-  var___switch_brk_4 := false;
-  if (((not (!var___switch_brk_4)) &&
-        ((!var___switch_hit_4) || (false || (var___switch_scrut_4 = 0l))))) {
-    var___switch_hit_4 := true;
+  let var___switch_scrut_8 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let mut var___switch_hit_8 : bool;
+  var___switch_hit_8 := false;
+  let mut var___switch_brk_8 : bool;
+  var___switch_brk_8 := false;
+  if (((not (!var___switch_brk_8)) &&
+        ((!var___switch_hit_8) || (false || (var___switch_scrut_8 = 0l))))) {
+    var___switch_hit_8 := true;
     return 10l;
   } else {};
-  var___switch_hit_4 := true;
+  var___switch_hit_8 := true;
   return 20l;
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_day_type.fst head/switch_stmt/Func_day_type.fst
index 3a0abdb..8c55998 100644
--- base/switch_stmt/Func_day_type.fst
+++ head/switch_stmt/Func_day_type.fst
@@ -22,26 +22,15 @@ divergent fn func_day_type (var_day: Typedef_int32_t.ty_int32_t)
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
   let var___switch_scrut_0 : Typedef_int32_t.ty_int32_t = (!var_day);
-  let mut var___switch_hit_0 : bool;
-  var___switch_hit_0 := false;
-  let mut var___switch_brk_0 : bool;
-  var___switch_brk_0 := false;
-  if (((not (!var___switch_brk_0)) &&
-        ((!var___switch_hit_0) ||
-          (((((false || (var___switch_scrut_0 = 1l)) || (var___switch_scrut_0 = 2l)) ||
-                (var___switch_scrut_0 = 3l))
-              ||
-              (var___switch_scrut_0 = 4l))
-            ||
-            (var___switch_scrut_0 = 5l))))) {
-    var___switch_hit_0 := true;
+  if ((((((var___switch_scrut_0 = 1l) || (var___switch_scrut_0 = 2l)) ||
+            (var___switch_scrut_0 = 3l))
+          ||
+          (var___switch_scrut_0 = 4l))
+        ||
+        (var___switch_scrut_0 = 5l))) {
     var_result := 1l;
-    var___switch_brk_0 := true;
-  } else {};
-  if ((not (!var___switch_brk_0))) {
-    var___switch_hit_0 := true;
+  } else {
     var_result := 0l;
-    var___switch_brk_0 := true;
-  } else {};
+  };
   return (!var_result);
 }
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases.fst head/switch_stmt/Func_default_after_cases.fst
new file mode 100644
index 0000000..399e3b5
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases.fst
@@ -0,0 +1,32 @@
+module Func_default_after_cases
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases (var_x: Typedef_int32_t.ty_int32_t)
+  requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  returns return_1 : Typedef_int32_t.ty_int32_t
+  ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+  ensures (with_pure (((id #int (Int32.v var_x)) = 0) ==> ((id #int (Int32.v return_1)) = 10)))
+  ensures (with_pure (((id #int (Int32.v var_x)) = 1) ==> ((id #int (Int32.v return_1)) = 20)))
+  ensures
+    (with_pure
+      (((not ((id #int (Int32.v var_x)) = 0)) && (not ((id #int (Int32.v var_x)) = 1))) ==>
+        ((id #int (Int32.v return_1)) = 30)))
+{
+  let mut var_x = var_x;
+  let mut var_r : Typedef_int32_t.ty_int32_t;
+  var_r := 0l;
+  let var___switch_scrut_2 : Typedef_int32_t.ty_int32_t = (!var_x);
+  if ((var___switch_scrut_2 = 0l)) {
+    var_r := 10l;
+  } else {
+    if ((var___switch_scrut_2 = 1l)) {
+      var_r := 20l;
+    } else {
+      var_r := 30l;
+    };
+  };
+  return (!var_r);
+}
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases.fsti head/switch_stmt/Func_default_after_cases.fsti
new file mode 100644
index 0000000..45131d7
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases.fsti
@@ -0,0 +1,16 @@
+module Func_default_after_cases
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases (var_x: Typedef_int32_t.ty_int32_t)
+requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+returns return_1 : Typedef_int32_t.ty_int32_t
+ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+ensures (with_pure (((id #int (Int32.v var_x)) = 0) ==> ((id #int (Int32.v return_1)) = 10)))
+ensures (with_pure (((id #int (Int32.v var_x)) = 1) ==> ((id #int (Int32.v return_1)) = 20)))
+ensures
+  (with_pure
+    (((not ((id #int (Int32.v var_x)) = 0)) && (not ((id #int (Int32.v var_x)) = 1))) ==>
+      ((id #int (Int32.v return_1)) = 30)))
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases_annotated.fst head/switch_stmt/Func_default_after_cases_annotated.fst
new file mode 100644
index 0000000..62fc7d8
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases_annotated.fst
@@ -0,0 +1,31 @@
+module Func_default_after_cases_annotated
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases_annotated (var_x: Typedef_int32_t.ty_int32_t)
+  requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  returns return_1 : Typedef_int32_t.ty_int32_t
+  ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+  ensures (with_pure (((id #int (Int32.v return_1)) = 10) || ((id #int (Int32.v return_1)) = 30)))
+{
+  let mut var_x = var_x;
+  let mut var_r : Typedef_int32_t.ty_int32_t;
+  var_r := 0l;
+  let var___switch_scrut_5 : Typedef_int32_t.ty_int32_t = (!var_x);
+  {
+    match (var___switch_scrut_5) {
+        0l -> {
+          var_r := 10l;
+        }
+      _ -> {
+        var_r := 30l;
+      }
+    };
+  }
+  ensures (((live var_x) ** (live var_r)) **
+    (with_pure (((id #int (Int32.v (!var_r))) = 10) || ((id #int (Int32.v (!var_r))) = 30))))
+  label __pal_match_join_0:;
+  return (!var_r);
+}
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases_annotated.fsti head/switch_stmt/Func_default_after_cases_annotated.fsti
new file mode 100644
index 0000000..f310941
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases_annotated.fsti
@@ -0,0 +1,11 @@
+module Func_default_after_cases_annotated
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases_annotated (var_x: Typedef_int32_t.ty_int32_t)
+requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+returns return_1 : Typedef_int32_t.ty_int32_t
+ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+ensures (with_pure (((id #int (Int32.v return_1)) = 10) || ((id #int (Int32.v return_1)) = 30)))
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases_no_break.fst head/switch_stmt/Func_default_after_cases_no_break.fst
new file mode 100644
index 0000000..6042e2f
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases_no_break.fst
@@ -0,0 +1,34 @@
+module Func_default_after_cases_no_break
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases_no_break (var_x: Typedef_int32_t.ty_int32_t)
+  requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  returns return_1 : Typedef_int32_t.ty_int32_t
+  ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+  ensures (with_pure (((id #int (Int32.v var_x)) = 0) ==> ((id #int (Int32.v return_1)) = 10)))
+  ensures
+    (with_pure ((not ((id #int (Int32.v var_x)) = 0)) ==> ((id #int (Int32.v return_1)) = 30)))
+{
+  let mut var_x = var_x;
+  let mut var_r : Typedef_int32_t.ty_int32_t;
+  var_r := 0l;
+  let var___switch_scrut_3 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let mut var___switch_hit_3 : bool;
+  var___switch_hit_3 := false;
+  let mut var___switch_brk_3 : bool;
+  var___switch_brk_3 := false;
+  if (((not (!var___switch_brk_3)) &&
+        ((!var___switch_hit_3) || (false || (var___switch_scrut_3 = 0l))))) {
+    var___switch_hit_3 := true;
+    var_r := 10l;
+    var___switch_brk_3 := true;
+  } else {};
+  if ((not (!var___switch_brk_3))) {
+    var___switch_hit_3 := true;
+    var_r := 30l;
+  } else {};
+  return (!var_r);
+}
\ No newline at end of file
diff --git head/switch_stmt/Func_default_after_cases_no_break.fsti head/switch_stmt/Func_default_after_cases_no_break.fsti
new file mode 100644
index 0000000..243bb00
--- /dev/null
+++ head/switch_stmt/Func_default_after_cases_no_break.fsti
@@ -0,0 +1,12 @@
+module Func_default_after_cases_no_break
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_after_cases_no_break (var_x: Typedef_int32_t.ty_int32_t)
+requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+returns return_1 : Typedef_int32_t.ty_int32_t
+ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+ensures (with_pure (((id #int (Int32.v var_x)) = 0) ==> ((id #int (Int32.v return_1)) = 10)))
+ensures (with_pure ((not ((id #int (Int32.v var_x)) = 0)) ==> ((id #int (Int32.v return_1)) = 30)))
\ No newline at end of file
diff --git head/switch_stmt/Func_default_before_cases.fst head/switch_stmt/Func_default_before_cases.fst
new file mode 100644
index 0000000..78e1d96
--- /dev/null
+++ head/switch_stmt/Func_default_before_cases.fst
@@ -0,0 +1,25 @@
+module Func_default_before_cases
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_before_cases (var_x: Typedef_int32_t.ty_int32_t)
+  requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  returns return_1 : Typedef_int32_t.ty_int32_t
+  ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+  ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+  ensures (with_pure (((id #int (Int32.v var_x)) = 1) ==> ((id #int (Int32.v return_1)) = 20)))
+  ensures
+    (with_pure ((not ((id #int (Int32.v var_x)) = 1)) ==> ((id #int (Int32.v return_1)) = 30)))
+{
+  let mut var_x = var_x;
+  let mut var_r : Typedef_int32_t.ty_int32_t;
+  var_r := 0l;
+  let var___switch_scrut_4 : Typedef_int32_t.ty_int32_t = (!var_x);
+  if ((var___switch_scrut_4 = 1l)) {
+    var_r := 20l;
+  } else {
+    var_r := 30l;
+  };
+  return (!var_r);
+}
\ No newline at end of file
diff --git head/switch_stmt/Func_default_before_cases.fsti head/switch_stmt/Func_default_before_cases.fsti
new file mode 100644
index 0000000..5578d49
--- /dev/null
+++ head/switch_stmt/Func_default_before_cases.fsti
@@ -0,0 +1,12 @@
+module Func_default_before_cases
+open Pulse
+open Pulse.Lib.C
+#lang-pulse
+
+divergent fn func_default_before_cases (var_x: Typedef_int32_t.ty_int32_t)
+requires ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+returns return_1 : Typedef_int32_t.ty_int32_t
+ensures ((Typedef_int32_t.ty_int32_t__pred var_x 1.0R))
+ensures ((Typedef_int32_t.ty_int32_t__pred return_1 1.0R))
+ensures (with_pure (((id #int (Int32.v var_x)) = 1) ==> ((id #int (Int32.v return_1)) = 20)))
+ensures (with_pure ((not ((id #int (Int32.v var_x)) = 1)) ==> ((id #int (Int32.v return_1)) = 30)))
\ No newline at end of file
diff --git base/switch_stmt/Func_sparse_string_name.fst head/switch_stmt/Func_sparse_string_name.fst
index 486a4f1..2b365bd 100644
--- base/switch_stmt/Func_sparse_string_name.fst
+++ head/switch_stmt/Func_sparse_string_name.fst
@@ -14,14 +14,14 @@ divergent fn func_sparse_string_name
   let mut var_fallback = var_fallback;
   let mut var_name : (ref Int8.t);
   var_name := (!var_fallback);
-  let var___switch_scrut_11 : Typedef_int32_t.ty_int32_t = (!var_x);
-  let mut var___switch_hit_11 : bool;
-  var___switch_hit_11 := false;
-  let mut var___switch_brk_11 : bool;
-  var___switch_brk_11 := false;
-  if (((not (!var___switch_brk_11)) &&
-        ((!var___switch_hit_11) || (false || (var___switch_scrut_11 = 100l))))) {
-    var___switch_hit_11 := true;
+  let var___switch_scrut_15 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let mut var___switch_hit_15 : bool;
+  var___switch_hit_15 := false;
+  let mut var___switch_brk_15 : bool;
+  var___switch_brk_15 := false;
+  if (((not (!var___switch_brk_15)) &&
+        ((!var___switch_hit_15) || (false || (var___switch_scrut_15 = 100l))))) {
+    var___switch_hit_15 := true;
     var_name :=
       (Pulse.Lib.C.Array.array_literal_to_ref
         (array_spec_of_list_with_len
@@ -36,12 +36,12 @@ divergent fn func_sparse_string_name
           (Cons #Int8.t (Int8.int_to_t 0)
           (Nil #Int8.t)))))))))
           8));
-    var___switch_brk_11 := true;
+    var___switch_brk_15 := true;
   } else {};
-  if (((not (!var___switch_brk_11)) &&
-        ((!var___switch_hit_11) ||
-          (false || (var___switch_scrut_11 = (Int32.sub Int32.zero 10l)))))) {
-    var___switch_hit_11 := true;
+  if (((not (!var___switch_brk_15)) &&
+        ((!var___switch_hit_15) ||
+          (false || (var___switch_scrut_15 = (Int32.sub Int32.zero 10l)))))) {
+    var___switch_hit_15 := true;
     var_name :=
       (Pulse.Lib.C.Array.array_literal_to_ref
         (array_spec_of_list_with_len
@@ -61,11 +61,11 @@ divergent fn func_sparse_string_name
           (Cons #Int8.t (Int8.int_to_t 0)
           (Nil #Int8.t))))))))))))))
           13));
-    var___switch_brk_11 := true;
+    var___switch_brk_15 := true;
   } else {};
-  if (((not (!var___switch_brk_11)) &&
-        ((!var___switch_hit_11) || (false || (var___switch_scrut_11 = 7l))))) {
-    var___switch_hit_11 := true;
+  if (((not (!var___switch_brk_15)) &&
+        ((!var___switch_hit_15) || (false || (var___switch_scrut_15 = 7l))))) {
+    var___switch_hit_15 := true;
     var_name :=
       (Pulse.Lib.C.Array.array_literal_to_ref
         (array_spec_of_list_with_len
@@ -78,7 +78,7 @@ divergent fn func_sparse_string_name
           (Cons #Int8.t (Int8.int_to_t 0)
           (Nil #Int8.t)))))))
           6));
-    var___switch_brk_11 := true;
+    var___switch_brk_15 := true;
   } else {};
   return (!var_name);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_sparse_unsorted.fst head/switch_stmt/Func_sparse_unsorted.fst
index 439e10e..627ac92 100644
--- base/switch_stmt/Func_sparse_unsorted.fst
+++ head/switch_stmt/Func_sparse_unsorted.fst
@@ -25,29 +25,29 @@ divergent fn func_sparse_unsorted (var_x: Typedef_int32_t.ty_int32_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_5 : Typedef_int32_t.ty_int32_t = (!var_x);
-  let mut var___switch_hit_5 : bool;
-  var___switch_hit_5 := false;
-  let mut var___switch_brk_5 : bool;
-  var___switch_brk_5 := false;
-  if (((not (!var___switch_brk_5)) &&
-        ((!var___switch_hit_5) || (false || (var___switch_scrut_5 = 100l))))) {
-    var___switch_hit_5 := true;
+  let var___switch_scrut_9 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let mut var___switch_hit_9 : bool;
+  var___switch_hit_9 := false;
+  let mut var___switch_brk_9 : bool;
+  var___switch_brk_9 := false;
+  if (((not (!var___switch_brk_9)) &&
+        ((!var___switch_hit_9) || (false || (var___switch_scrut_9 = 100l))))) {
+    var___switch_hit_9 := true;
     var_result := 3l;
-    var___switch_brk_5 := true;
+    var___switch_brk_9 := true;
   } else {};
-  if (((not (!var___switch_brk_5)) &&
-        ((!var___switch_hit_5) ||
-          (false || (var___switch_scrut_5 = (Int32.sub Int32.zero 10l)))))) {
-    var___switch_hit_5 := true;
+  if (((not (!var___switch_brk_9)) &&
+        ((!var___switch_hit_9) ||
+          (false || (var___switch_scrut_9 = (Int32.sub Int32.zero 10l)))))) {
+    var___switch_hit_9 := true;
     var_result := 1l;
-    var___switch_brk_5 := true;
+    var___switch_brk_9 := true;
   } else {};
-  if (((not (!var___switch_brk_5)) &&
-        ((!var___switch_hit_5) || (false || (var___switch_scrut_5 = 7l))))) {
-    var___switch_hit_5 := true;
+  if (((not (!var___switch_brk_9)) &&
+        ((!var___switch_hit_9) || (false || (var___switch_scrut_9 = 7l))))) {
+    var___switch_hit_9 := true;
     var_result := 2l;
-    var___switch_brk_5 := true;
+    var___switch_brk_9 := true;
   } else {};
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_i32.fst head/switch_stmt/Func_terminal_break_i32.fst
index 1365a2f..c0a48ec 100644
--- base/switch_stmt/Func_terminal_break_i32.fst
+++ head/switch_stmt/Func_terminal_break_i32.fst
@@ -13,9 +13,9 @@ divergent fn func_terminal_break_i32 (var_x: Typedef_int32_t.ty_int32_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_6 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let var___switch_scrut_10 : Typedef_int32_t.ty_int32_t = (!var_x);
   {
-    match (var___switch_scrut_6) {
+    match (var___switch_scrut_10) {
         -10l -> {
           var_result := 1l;
         }
@@ -28,6 +28,6 @@ divergent fn func_terminal_break_i32 (var_x: Typedef_int32_t.ty_int32_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_1:;
+  label __pal_match_join_2:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_i64.fst head/switch_stmt/Func_terminal_break_i64.fst
index 07fa590..4736d42 100644
--- base/switch_stmt/Func_terminal_break_i64.fst
+++ head/switch_stmt/Func_terminal_break_i64.fst
@@ -13,9 +13,9 @@ divergent fn func_terminal_break_i64 (var_x: Typedef_int64_t.ty_int64_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_9 : Typedef_int64_t.ty_int64_t = (!var_x);
+  let var___switch_scrut_13 : Typedef_int64_t.ty_int64_t = (!var_x);
   {
-    match (var___switch_scrut_9) {
+    match (var___switch_scrut_13) {
         -1L -> {
           var_result := 1l;
         }
@@ -25,6 +25,6 @@ divergent fn func_terminal_break_i64 (var_x: Typedef_int64_t.ty_int64_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_4:;
+  label __pal_match_join_5:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_promoted_u8.fst head/switch_stmt/Func_terminal_break_promoted_u8.fst
index 0d6d313..08b74d5 100644
--- base/switch_stmt/Func_terminal_break_promoted_u8.fst
+++ head/switch_stmt/Func_terminal_break_promoted_u8.fst
@@ -13,9 +13,9 @@ divergent fn func_terminal_break_promoted_u8 (var_x: Typedef_uint8_t.ty_uint8_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_8 : Int32.t = (id #Int32.t (Int.Cast.uint8_to_int32 (!var_x)));
+  let var___switch_scrut_12 : Int32.t = (id #Int32.t (Int.Cast.uint8_to_int32 (!var_x)));
   {
-    match (var___switch_scrut_8) {
+    match (var___switch_scrut_12) {
         255l -> {
           var_result := 1l;
         }
@@ -25,6 +25,6 @@ divergent fn func_terminal_break_promoted_u8 (var_x: Typedef_uint8_t.ty_uint8_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_3:;
+  label __pal_match_join_4:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_scale.fst head/switch_stmt/Func_terminal_break_scale.fst
index a206cf6..c908d53 100644
--- base/switch_stmt/Func_terminal_break_scale.fst
+++ head/switch_stmt/Func_terminal_break_scale.fst
@@ -13,55 +13,55 @@ divergent fn func_terminal_break_scale (var_x: Typedef_int32_t.ty_int32_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_12 : Typedef_int32_t.ty_int32_t = (!var_x);
+  let var___switch_scrut_16 : Typedef_int32_t.ty_int32_t = (!var_x);
   {
-    match (var___switch_scrut_12) {
-        33l -> {
+    match (var___switch_scrut_16) {
+        43l -> {
           var_result := 1l;
         }
-        34l -> {
+        44l -> {
           var_result := 1l;
         }
-        35l -> {
+        45l -> {
           var_result := 1l;
         }
-        36l -> {
+        46l -> {
           var_result := 1l;
         }
-        37l -> {
+        47l -> {
           var_result := 1l;
         }
-        38l -> {
+        48l -> {
           var_result := 1l;
         }
-        39l -> {
+        49l -> {
           var_result := 1l;
         }
-        40l -> {
+        50l -> {
           var_result := 1l;
         }
-        41l -> {
+        51l -> {
           var_result := 1l;
         }
-        42l -> {
+        52l -> {
           var_result := 1l;
         }
-        43l -> {
+        53l -> {
           var_result := 1l;
         }
-        44l -> {
+        54l -> {
           var_result := 1l;
         }
-        45l -> {
+        55l -> {
           var_result := 1l;
         }
-        46l -> {
+        56l -> {
           var_result := 1l;
         }
-        47l -> {
+        57l -> {
           var_result := 1l;
         }
-        48l -> {
+        58l -> {
           var_result := 1l;
         }
       _ -> {}
@@ -70,6 +70,6 @@ divergent fn func_terminal_break_scale (var_x: Typedef_int32_t.ty_int32_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_6:;
+  label __pal_match_join_7:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_u32.fst head/switch_stmt/Func_terminal_break_u32.fst
index cdf9530..8450d1b 100644
--- base/switch_stmt/Func_terminal_break_u32.fst
+++ head/switch_stmt/Func_terminal_break_u32.fst
@@ -13,9 +13,9 @@ divergent fn func_terminal_break_u32 (var_x: Typedef_uint32_t.ty_uint32_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_7 : Typedef_uint32_t.ty_uint32_t = (!var_x);
+  let var___switch_scrut_11 : Typedef_uint32_t.ty_uint32_t = (!var_x);
   {
-    match (var___switch_scrut_7) {
+    match (var___switch_scrut_11) {
         0ul -> {
           var_result := 1l;
         }
@@ -28,6 +28,6 @@ divergent fn func_terminal_break_u32 (var_x: Typedef_uint32_t.ty_uint32_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_2:;
+  label __pal_match_join_3:;
   return (!var_result);
 }
\ No newline at end of file
diff --git base/switch_stmt/Func_terminal_break_u64.fst head/switch_stmt/Func_terminal_break_u64.fst
index f5e9ec7..48b2106 100644
--- base/switch_stmt/Func_terminal_break_u64.fst
+++ head/switch_stmt/Func_terminal_break_u64.fst
@@ -13,9 +13,9 @@ divergent fn func_terminal_break_u64 (var_x: Typedef_uint64_t.ty_uint64_t)
   let mut var_x = var_x;
   let mut var_result : Typedef_int32_t.ty_int32_t;
   var_result := 0l;
-  let var___switch_scrut_10 : Typedef_uint64_t.ty_uint64_t = (!var_x);
+  let var___switch_scrut_14 : Typedef_uint64_t.ty_uint64_t = (!var_x);
   {
-    match (var___switch_scrut_10) {
+    match (var___switch_scrut_14) {
         0uL -> {
           var_result := 1l;
         }
@@ -28,6 +28,6 @@ divergent fn func_terminal_break_u64 (var_x: Typedef_uint64_t.ty_uint64_t)
   ensures (((live var_x) ** (live var_result)) **
     (with_pure
       (((id #int (Int32.v (!var_result))) = 0) || ((id #int (Int32.v (!var_result))) = 1))))
-  label __pal_match_join_5:;
+  label __pal_match_join_6:;
   return (!var_result);
 }
\ No newline at end of file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants