The main goal here is to support quantifiers in specs for static analysis, because it's unclear how they'd be runtime checked.
Quantifiers are necessary to express e.g. algebraic properties.
For example, to specify the concept of a group, we should be able to write the following:
#[spec(
maintains: [
// The group has an identity element.
forall(|x: Self| x.op(&Self::IDENTITY) == x && Self::IDENTITY.op(&x) == x),
// The binary operation is associative.
forall(|x: Self, y: Self, z: Self| x.op(&y).op(&z) == x.op(&y.op(&z))),
],
)]
trait Group: Eq + PartialEq + Sized {
const IDENTITY: Self;
fn op(&self, other: &Self) -> Self;
#[spec(
ensures: [
self.op(output) == Self::IDENTITY,
output.op(self) == Self::IDENTITY,
],
)]
fn inverse(&self) -> Self;
}
Note that associativity involves 3 variables, even though op only has two inputs.
The main goal here is to support quantifiers in specs for static analysis, because it's unclear how they'd be runtime checked.
Quantifiers are necessary to express e.g. algebraic properties.
For example, to specify the concept of a group, we should be able to write the following:
Note that associativity involves 3 variables, even though
oponly has two inputs.