Permission type and parameter

Having a fixed permission amount in the contract is restrictive. For example, clients with only acc(r, 1/4) cannot call p.sum():

type pair struct {
	left, right int
}

// @ requires acc(p, 1/2)
// @ ensures acc(p, 1/2)
// @ ensures s == p.left + p.right
func (p *pair) sum() (s int) {
	return p.left + p.right
}

// @ requires acc(p, 1/4)
// @ requires p.left == 2 && p.right == 3
func client(p *pair) {
	res := p.sum()
	// @ assert res == 5
}
ERROR Precondition of call p.sum() might not hold. 
Permission to p might not suffice.

One option is to use the wildcard permission amount, as previously studied, which comes with its own drawbacks. In this section, we show how to abstract the exact permission amount by introducing a ghost parameter of type perm, i.e. Gobra's type for permission amounts:

type pair struct {
	left, right int
}

// @ requires a > 0	    // <--- added
// @ requires acc(p, a) // <--- changed
// @ ensures acc(p, a)	// <--- changed
// @ ensures s == p.left + p.right
func (p *pair) sum( /*@ ghost a perm @*/ ) (s int) { // <--- new parameter
	return p.left + p.right
}

// @ requires acc(p, 1/2)
// @ requires p.left == 2 && p.right == 3
func client(p *pair) {
	res := p.sum( /*@ 1/4 @*/ )  // <--- changed
	// @ assert res == 5
}

Conventionally the permission amount is called p, which clashes here with our pair pointer. When calling sum, we must pass the permission amount: p.sum( /*@ 1/4 @*/ ). The precondition p > 0 is important to get read permission, otherwise we get:

ERROR Method contract is not well-formed.
Expression p might be negative.

Permission arithmetic

We may convert a fraction to a permission amount and perform calculations with it:

func main() {
	assert perm(1/2) + perm(1/2) == writePerm
	assert perm(1) - 1/2 == perm(1/2)
	assert perm(1/2) * 0 == noPerm
	assert perm(1) / 2 != writePerm
	assert perm(1/3) == 1/3
	assert perm(perm(1/3)) == perm(1/3)
}

Note that for access predicates, we can, and have been using the shorthand acc(p, 1/2) instead of acc(p, perm(1/2)).