Skip to content

New Pure Function Encoding#163

Open
jaspergeer wants to merge 32 commits into
Aurel300:rewrite-2023from
jaspergeer:pure-fns
Open

New Pure Function Encoding#163
jaspergeer wants to merge 32 commits into
Aurel300:rewrite-2023from
jaspergeer:pure-fns

Conversation

@jaspergeer
Copy link
Copy Markdown

@jaspergeer jaspergeer commented Mar 28, 2026

This PR re-implements the encoding of pure functions. It solves two problems:

  • Previously, we were verifying both the impure encoding and pure encoding of each function. It was possible that the impure encoding verified while the pure encoding did not.
  • Functions on references to recursive data structures would not be unfolded along with their argument's referent, causing programs to fail to verify without extra annotation.

Changes

There are changes to existing encoders in this PR:

  • TyPure now generates a trig function for every type, which takes a snapshot and returns a boolean.
  • TyUsePure's interface exposes some utility functions for calling trig functions.
  • MirLocalDefEnc also generates a trig function application. For ADTs, this applies the type's trig function to the local's snapshot. For Refs, this applies the referent type's trig function to the referent's snapshot.
  • MirImpure emits, when encoding a place, inhales of trig applications for that place and any projections whose type is an ADT. When encoding an Aggregate rvalue, an instance of trig applied to the snapshot of the aggregate value is emitted.
  • FunctionEnc now encodes functions using a manual axiomatization, which is described in the next section.

This PR adds some tests:

  • verify/pass/pure-fn/list-enum.rs
  • verify/pass/pure-fn/list-enum-poly.rs
  • verify/pass/pure-fn/pure-spec.rs
  • verify/fail/pure-fn/list-enum-fail.rs
  • verify/fail/pure-fn/pure-spec-fail.rs

The first two tests fail to verify in the current version of Prusti because they rely on function definitions being unfolded alongside the referent of an argument. The second two tests exist as a smoke test for soundness bugs.

In addition, the following were moved to tests:

  • tests_old/verify/fail/demos/append-sorted-error-{1,2,4}.rs
  • tests_old/verify/pass/demos/append-sorted.rs passes

Design

The encoding of a pure function:

#[pure]
#[requires(<pre>)]
#[ensures(<post>)]
f(arg0: T0, ... argn: Tn): Tr 
{
	<body>
}

is as follows:

domain PureFns {
    function unlimited_f(arg0: [T0], ..., argn: [Tn]): [Tr]
	
    function limited_f(arg0: [T0], ..., argn: [Tn]): [Tr]
	
    axiom Defn_f {
        forall arg0: [T0], ..., argn: [Tn] ::
        { unlimited_f(arg0, ..., argn) }
        <arg0-triggers>
        ...
        <argn-triggers>
        unlimited_f(arg0, ..., argn) ==
            [<body>](arg0, ..., argn)
    }
    
    axiom Limited_f {
        forall arg0: [T0], ..., argn: [Tn] ::
        { unlimited_f(arg0, ..., argn) }
        unlimited_f(arg0, ..., argn) == limited_f(arg0, ..., argn)
    }
	
    <trig-fns>
}

function caller_f(arg0: [T0], ..., argn: [Tn]): [Tr]
    requires [<pre>](arg0, ..., argn)
    ensures [ [<post>](arg0, ..., argn, <result>), true ]
{
    unlimited_f(arg0, ..., argn)
}

where:

[T] refers to the snapshot-based encoding of T.

[<body>](arg0, ..., argn) is the pure encoding of <body> with free variable substitutions arg0, ..., argn.
The free variables of a body are the ordered function arguments followed by the 'return place', if it can be referenced.
Note that the pure encoding will be modified to encode recursive calls to f as calls to limited_f.

<trig-fns> contains an opaque function function trig_s_T([T]): Bool for each ADT T.

<argi-triggers> is { limited_f(arg0, ..., argn), trig_s_T(make_concrete_s_T(argi.s_Ref_immutable_1)) } if Ti is an immutable reference type and T is an ADT such that &T = Ti.
<argi-triggers> is { limited_f(arg0, ..., argn), trig_s_Ti(argi) } if Ti is an ADT.
<argi-triggers> is empty otherwise.

Note: here I take the naive approach of triggering on the unfolding of any ADT parameter - if it turns out that this has too much of a performance impact, we could try analyzing type definitions to restrict triggers to recursive types and try analyzing the body of a pure function to identify which parameters are unfolded around a recursive call

[<pre>](arg0, ..., argn) and [<post>](arg0, ..., argn, ret) and [<post>](arg0, ..., argn, <result>) are the pure encodings of <pre> and <post> with free variable substitutions.
Observe that the encoding of the post condition appears inside of an inhale-exhale statement. As a result, Viper will trust that the body of caller_f satisfies the spec.

Impure Encoding

When a pure function f is called from impure code, this is encoded as a call to caller_f.

We inhale instances of trig_s_T for instances of s_T which occur in assignment statement rvalues (they may be projections of the root place).
We also inhale an instance of trig_s_T for the snapshot encoding of Aggregate rvalues, which correspond to ADT constructions.
We also inhale an instance of trig_s_T for the PCG operation RepackExpand.

@jaspergeer jaspergeer marked this pull request as draft March 28, 2026 00:56
@Aurel300
Copy link
Copy Markdown
Owner

Re: tests, do the tests in the second category mentioned here (the ones which mention "better recursive pure functions") now verify?

@jaspergeer
Copy link
Copy Markdown
Author

jaspergeer commented Apr 23, 2026

Re: tests, do the tests in the second category mentioned here (the ones which mention "better recursive pure functions") now verify?

  • tests_old/verify/fail/demos/append-sorted-error-{1,2,4}.rs all fail correctly
  • tests_old/verify/pass/demos/append-sorted.rs passes

The remaining 3 cause panics but they do on rewrite-2023 as well.

@jaspergeer jaspergeer marked this pull request as ready for review April 24, 2026 00:56
@jaspergeer jaspergeer marked this pull request as draft April 24, 2026 03:07
@jaspergeer jaspergeer marked this pull request as ready for review April 24, 2026 21:54
@JonasAlaif JonasAlaif requested review from Aurel300 and JonasAlaif May 4, 2026 15:12
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