prusti-dev icon indicating copy to clipboard operation
prusti-dev copied to clipboard

Support for library contracts

Open jjurm opened this issue 3 years ago • 5 comments

Summary: Automatically import specifications from dependency crates and inline them when respective functions or types are referenced in the current crate.

This eliminates the need for #[extern_spec] blocks for declarations in other crates as long as the crates are compiled in the same cargo session.

With the proposed changes, the following verifies: prusti-tests/tests/cargo_verify/library_contracts_test/src/main.rs:

extern crate prusti_contracts;
extern crate library_contracts_lib;

use library_contracts_lib::Opt;

// Demonstrating library contracts: the following specification is imported
// and thus the #[extern_spec] block is not needed

/*
use prusti_contracts::*;
#[extern_spec]
impl<T> Opt<T> {
    #[ensures(matches!(*self, Opt::OSome(_)) == result)]
    fn is_some(&self) -> bool;
}
*/

fn main() {
    let a = Opt::OSome(42);
    let b = Opt::ONone::<i32>;

    assert!(a.is_some() == true);
    assert!(b.is_some() == false);
}

Closes #2

jjurm avatar Jul 13 '22 05:07 jjurm

TO-DO:

  • [x] Load specs only from dependency crates instead of loading all compiled crates
  • [x] Ensure that serialized specs are usable across subsequent builds

jjurm avatar Jul 13 '22 05:07 jjurm

@jjurm also try changing the CLEAR_CROSS_CRATE flag to see what it does, I have no idea but maybe it'll help with the recompilation issue?

JonasAlaif avatar Jul 25 '22 21:07 JonasAlaif

If you have time, could you also try to fix the crash I've introduced now - I didn't have time now before going on holiday

JonasAlaif avatar Jul 25 '22 21:07 JonasAlaif

By the way, will this functionality also work for items that are both in core and std? For example, the method core::mem::swap is also re-exported as std::mem::swap by the standard library. If an #[extern_spec] is defined for one of these paths, will it also automatically work for the other? This is handy for #![no_std] crates that are verified with Prusti, which typically import everything from the core::* namespace instead of from the std::* namespace.

Pointerbender avatar Aug 12 '22 08:08 Pointerbender

@Pointerbender This discussion is starting to overlap quite a bit with @juliand665's thesis. (Also for that reason @jjurm the solution in this PR does not yet have to be perfect.) Our plan is indeed to support both core and std, maybe in addition to some third-party libraries. For more info, see the project description.

As you say, std re-rexports many modules from core, e.g. here for Option. Because extern specs bind to a method by its DefId, then the methods of option are the one and the same, no matter what path you used to access them.

Aurel300 avatar Aug 12 '22 08:08 Aurel300

Ooof... this should be ready to merge now if CI checks pass. If you want, we can discuss a bit before then @Aurel300?

JonasAlaif avatar Aug 22 '22 18:08 JonasAlaif

Generally looks good! I wish it wasn't a PR that combined so many changes:

  • support cross-crate specs;
  • refactor build process for loading prusti-contracts and core/std specs;
  • refactor Environment into separate parts (+ adapt rest of codebase).

Although you documented MIN_PRUSTI_VERSION, I think we should document the contracts feature/crate more thoroughly in the user guide, as there are probably some pitfalls. We can push that onto another PR though, since this one is large and will easily get into conflicts.

Aurel300 avatar Aug 25 '22 15:08 Aurel300

bors r+

JonasAlaif avatar Aug 26 '22 15:08 JonasAlaif

bors r+

JonasAlaif avatar Aug 27 '22 07:08 JonasAlaif

Build failed:

bors[bot] avatar Aug 27 '22 07:08 bors[bot]

bors r+

JonasAlaif avatar Aug 28 '22 15:08 JonasAlaif

Build failed:

bors[bot] avatar Aug 28 '22 16:08 bors[bot]

bors r+

JonasAlaif avatar Aug 28 '22 17:08 JonasAlaif

Build failed:

bors[bot] avatar Aug 28 '22 21:08 bors[bot]

bors r+

JonasAlaif avatar Aug 29 '22 12:08 JonasAlaif