Skip to content

Commit 0151e2b

Browse files
nikswamyCopilot
andcommitted
Comprehensive extraction regression test for Pulse fn interleaving
ExtractPulseFnIface: expanded test covering all interleaving patterns between .fsti and .fst for DeclToBeDesugared (Pulse fn) declarations: 1. val + let (basic, always worked) 2. fn in .fsti matched by fn in .fst 3. Private helper in .fst before interface fns (skip, not mark private) 4. Out-of-order exposed definitions (fsti: write_and_return, assign_ref; fst: assign_ref first, then let write_and_return = assign_ref) 5. let alias in .fst implementing fn in .fsti 6. let definition in .fsti interleaved before fn declarations Verifies that all 8 functions extract to C with correct visibility: - private_helper → static (private) - all interface-exposed fns → public - function pointer aliases → correct Also comments out --cmi in mk/test.mk since --cmi is now default in fstar2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a8bdbb9 commit 0151e2b

4 files changed

Lines changed: 126 additions & 6 deletions

File tree

mk/test.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ include $(PULSE_ROOT)/mk/locate.mk
2525

2626
HINTS_ENABLED?=
2727

28-
OTHERFLAGS += --cmi
28+
# OTHERFLAGS += --cmi # now default in fstar2
2929
# This warning is really useless.
3030
OTHERFLAGS += --warn_error -321
3131
OTHERFLAGS += --warn_error @247 # couldn't write a checked file? FAIL RIGHT NOW

test/bug-reports/ExtractPulseFnIface.c.expected

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,32 @@ krml_checked_int_t ExtractPulseFnIface_pulse_read_ref(krml_checked_int_t *r)
1515
return *r;
1616
}
1717

18+
krml_checked_int_t ExtractPulseFnIface_double(krml_checked_int_t x)
19+
{
20+
return ExtractPulseFnIface_pure_add(x, x);
21+
}
22+
23+
static void private_helper(krml_checked_int_t *r, krml_checked_int_t v)
24+
{
25+
*r = v;
26+
}
27+
28+
void ExtractPulseFnIface_pulse_write_ref(krml_checked_int_t *r, krml_checked_int_t v)
29+
{
30+
private_helper(r, v);
31+
}
32+
33+
krml_checked_int_t ExtractPulseFnIface_assign_ref(krml_checked_int_t *r, krml_checked_int_t v)
34+
{
35+
*r = v;
36+
return v;
37+
}
38+
39+
krml_checked_int_t
40+
(*ExtractPulseFnIface_write_and_return)(krml_checked_int_t *x0, krml_checked_int_t x1) =
41+
ExtractPulseFnIface_assign_ref;
42+
43+
krml_checked_int_t
44+
(*ExtractPulseFnIface_pulse_read_ref2)(krml_checked_int_t *x0) =
45+
ExtractPulseFnIface_pulse_read_ref;
46+

test/bug-reports/ExtractPulseFnIface.fst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ open Pulse.Lib.Pervasives
55
open Pulse.Lib.Reference
66
module R = Pulse.Lib.Reference
77

8+
// Pattern 1: val + let (basic)
89
let pure_add (x y : int) : int = x + y
910

11+
// Pattern 2: fn matched by fn
1012
fn pulse_read_ref
1113
(r: ref int)
1214
(#v: Ghost.erased int)
@@ -17,3 +19,47 @@ fn pulse_read_ref
1719
let x = !r;
1820
x
1921
}
22+
23+
// Pattern 3: Private helper NOT in .fsti — interleaver must skip past
24+
// interface entries to avoid marking this as KrmlPrivate erroneously.
25+
fn private_helper
26+
(r: ref int)
27+
(v: int)
28+
(#old: Ghost.erased int)
29+
requires R.pts_to r old
30+
ensures R.pts_to r v
31+
{
32+
r := v
33+
}
34+
35+
// Pattern 3 (continued): exposed fn after private helper
36+
fn pulse_write_ref
37+
(r: ref int)
38+
(v: int)
39+
(#old: Ghost.erased int)
40+
requires R.pts_to r old
41+
ensures R.pts_to r v
42+
{
43+
private_helper r v
44+
}
45+
46+
// Pattern 4: Out-of-order — .fsti has write_and_return BEFORE assign_ref,
47+
// but .fst defines assign_ref first and write_and_return as an alias.
48+
// The interleaver must skip past write_and_return in the interface to
49+
// match assign_ref, then come back for write_and_return.
50+
fn assign_ref
51+
(r: ref int)
52+
(v: int)
53+
(#old: Ghost.erased int)
54+
requires R.pts_to r old
55+
returns x: int
56+
ensures R.pts_to r v ** pure (x == v)
57+
{
58+
r := v;
59+
v
60+
}
61+
62+
let write_and_return = assign_ref
63+
64+
// Pattern 5: let alias in .fst implementing fn in .fsti
65+
let pulse_read_ref2 = pulse_read_ref
Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,66 @@
11
module ExtractPulseFnIface
22
#lang-pulse
33

4-
(** Interface for ExtractPulseFnIface.
5-
Tests that a Pulse fn declared in .fsti extracts to C correctly.
6-
Regression test: previously, fn declarations in .fsti were not
7-
recognized by the interleaver, causing the implementation to be
8-
tagged KrmlPrivate and silently dropped by KaRaMeL. *)
4+
(** Regression test for interleaving DeclToBeDesugared (Pulse fn) in .fsti/.fst.
5+
Tests that all patterns extract to C correctly without KrmlPrivate.
6+
7+
Patterns tested:
8+
1. val + let (basic, always worked)
9+
2. fn in .fsti + fn in .fst (basic DeclToBeDesugared matching)
10+
3. Private helper in .fst before interface fns (skip, not mark private)
11+
4. Out-of-order exposed definitions (fsti: write, assign; fst: assign, let write=assign)
12+
5. let alias in .fst implementing fn in .fsti
13+
6. fn in .fsti with let definitions before fn declarations *)
914

1015
open Pulse.Lib.Pervasives
1116
open Pulse.Lib.Reference
1217
module R = Pulse.Lib.Reference
1318

19+
// Pattern 1: val + let (basic)
1420
val pure_add (x y : int) : int
1521

22+
// Pattern 2: fn in .fsti matched by fn in .fst
1623
fn pulse_read_ref
1724
(r: ref int)
1825
(#v: Ghost.erased int)
1926
requires R.pts_to r v
2027
returns x: int
2128
ensures R.pts_to r v ** pure (x == Ghost.reveal v)
29+
30+
// Pattern 6: let definition in .fsti before fn declarations
31+
let double (x: int) : int = pure_add x x
32+
33+
// Pattern 3: .fst will have a private helper before this fn
34+
fn pulse_write_ref
35+
(r: ref int)
36+
(v: int)
37+
(#old: Ghost.erased int)
38+
requires R.pts_to r old
39+
ensures R.pts_to r v
40+
41+
// Pattern 4: Out-of-order — .fsti has write_and_return before assign_ref,
42+
// but .fst defines assign_ref first (as the primary fn) and then
43+
// let write_and_return = assign_ref as an alias.
44+
fn write_and_return
45+
(r: ref int)
46+
(v: int)
47+
(#old: Ghost.erased int)
48+
requires R.pts_to r old
49+
returns x: int
50+
ensures R.pts_to r v ** pure (x == v)
51+
52+
fn assign_ref
53+
(r: ref int)
54+
(v: int)
55+
(#old: Ghost.erased int)
56+
requires R.pts_to r old
57+
returns x: int
58+
ensures R.pts_to r v ** pure (x == v)
59+
60+
// Pattern 5: fn in .fsti, let alias in .fst
61+
fn pulse_read_ref2
62+
(r: ref int)
63+
(#v: Ghost.erased int)
64+
requires R.pts_to r v
65+
returns x: int
66+
ensures R.pts_to r v ** pure (x == Ghost.reveal v)

0 commit comments

Comments
 (0)