Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/language-top.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ field next: Ref

* Declared by keyword `field`
* Every object has all fields (there are no classes in Viper)
* Several fields may be declared at once, e.g., `field val: Int, next: Ref`
* See the [section on permissions](./permissions.md) for examples

## Methods
Expand All @@ -28,6 +29,7 @@ method QSort(xs: Seq[Ref]) returns (ys: Seq[Ref])
* Hence calls _cannot_ be used in specifications
* Modular verification of methods and method calls
* The body may include some number of _statements_ (including recursive calls)
* The body is optional: a method without a body is _abstract_. Since verification is modular, calls to abstract methods are verified against their specification as usual; abstract methods are useful, e.g., to model the behaviour of library code
* The body is invisible at call site (changing the body does not affect client code)
* The precondition is checked before the method call (more precisely, it is [_exhaled_](./permissions-inhale-exhale.md))
* The postcondition is assumed after the method call (more precisely, it is [_inhaled_](./permissions-inhale-exhale.md))
Expand Down Expand Up @@ -91,6 +93,21 @@ domain Pair[A, B] {
* Useful for specifying custom mathematical theories
* See the [section on domains](./domains.md) for details

## Algebraic data types {#intro-adts}

```viper
adt List[T] {
Nil()
Cons(value: T, tail: List[T])
}
```

* Declared by keyword `adt` (provided by a plugin that is enabled by default)
* Have a name, which is introduced as an additional _type_ in the Viper program, and may have type parameters (e.g. `T` above)
* The body declares the _constructors_ of the datatype (e.g. `Nil` and `Cons` above)
* Viper automatically generates _destructors_ (e.g. `xs.value`, `xs.tail`) and _discriminators_ (e.g. `xs.isNil`, `xs.isCons`)
* See the [section on the ADT plugin](./domains-adt.md) for details

## Macros

```viper
Expand Down
6 changes: 6 additions & 0 deletions src/statements-assignments.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ to all (possibly none) fields listed comma-separated within the parentheses. As
*all* fields declared in the Viper program. Note that neither method calls nor
object creation are expressions. Hence, they must not occur as receivers, method
arguments, etc.; instead of nesting these constructs, one typically assigns their results first to local variables, and then uses these.

Viper additionally supports some more flexible forms of declarations and assignments:

* Local variable declarations may declare several variables at once, e.g., `var a: Ref, b: Ref, c: Int`.
* Local variable declarations may include an initial assignment, e.g., `var x: Int := 5`; the right-hand side may also be a method call or object creation, e.g., `var y: Ref := new(*)`.
* Heap locations and newly-declared local variables may occur on the left-hand sides of method calls and object creations, e.g., `x.f := new(...)` and `a, x.f := m(...)`.
54 changes: 54 additions & 0 deletions src/statements-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,57 @@ follows:
3. Exhale the loop invariant.

Analogous to functions, Viper does also *not* check loop (or method) termination per default, see the [chapter on termination](./termination.md) for more details. Alternatively, custom termination checks can be encoded through suitable assertions (see the *labelled old expressions* described in the [section on expressions](./expressions-multi.md)).

## Labels and gotos

In addition to the structured control flow constructs shown above, Viper supports labels and unconditional jumps:

```viper
label l
goto l
```

A `label` statement declares a program point with the given name. Labels serve two purposes: they can be the target of `goto` statements, and they can be referred to in [labelled old expressions](./expressions-multi.md) `old[l](e)`. A `goto` statement transfers control to the given label. Since Viper is primarily an intermediate language, gotos are mainly intended for encoding the unstructured control flow of front-end languages (for example, `break` and `continue` statements, or early returns); Viper programs must not use gotos to create *irreducible* control flow (e.g., jumps from outside a loop into the middle of the loop body).

A `goto` that jumps out of a `while` loop exits the loop *without* checking the loop invariant; permissions held before the loop that were not transferred into it via the invariant become available again after the jump. Loops can also be created by jumping *backwards* to a label. To support invariants for such loops, `label` declarations may be directly followed by `invariant` clauses; a label's stated invariant is used only if the label is in fact a loop head. Both features are illustrated in the following example:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warn that using this feature carelessly might lead to unsoundness? (E.g., invariant on a label that is not actually a loop head, trying to place multiple invariants in the same CFG loop, ...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might it? If you put an invariant on a label that's not a loop head it should simply be ignored. The text could make that clearer, but that should not make anything unsound. Nor should placing multiple invariants in the same loop afaik? If it does, that sounds like a problem we should fix yesterday.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't you talk with Jonáš about this recently? x) Even so, the silently ignoring part should be addressed and pointed out here as a (current) limitation. Maybe it's not strictly unsound but...?

method test() {
    var x: Int := 0
label head
    invariant 0 <= x <= 10
label body
    invariant false // this is fine
    if (x >= 10) {
        goto end
    }
    x := x + 1
    goto head
label end
    assert x == 10
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, yes, we should say it's silently ignored. And we could also just fix that and emit a warning when we see an invariant on a non-loop-head.
But it's an auxiliary proof annotation. No postcondition and no assert verifies that shouldn't verify, IMO there is absolutely nothing unsound going on here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can adapt and merge this once we've discussed whether it should be a warning or an error.


```viper,editable,playground
method firstPositive(xs: Seq[Int]) returns (idx: Int)
ensures idx >= 0 ==> idx < |xs| && xs[idx] > 0
{
idx := -1
var i: Int := 0
while (i < |xs|)
invariant 0 <= i && i <= |xs|
invariant idx == -1
{
if (xs[i] > 0) {
idx := i
// exits the loop; the invariant idx == -1 does not hold here,
// but invariants are not checked when jumping out of a loop
goto done
}
i := i + 1
}
label done
}

method countdown(n: Int)
requires 0 <= n
{
var i: Int := n
// this label is the head of a loop created by the backward goto
// below, so its invariant is used to verify the loop
label head
invariant 0 <= i
if (i > 0) {
i := i - 1
goto head
}
assert i == 0
}
```

> **Exercise**
> * In `countdown`, remove the `invariant` clause on the label `head`. Which assertion fails, and why?
> * In `firstPositive`, remove the `goto done` statement (so that the loop always runs to completion). The invariant `idx == -1` now fails to verify — why was it not checked before, when the `goto` statement was still present?
Loading