Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing (!new) check #4926

Closed
RustanLeino opened this issue Jan 2, 2024 · 1 comment · Fixed by #4928
Closed

Missing (!new) check #4926

RustanLeino opened this issue Jan 2, 2024 · 1 comment · Fixed by #4928
Assignees
Labels
kind: bug Crashes, unsoundness, incorrect output, etc. If possible, add a `part:` label part: resolver Resolution and typechecking

Comments

@RustanLeino
Copy link
Collaborator

Dafny version

4.4.0

Code to produce this issue

function F<A(!new)>(): int

class Cell { }

lemma Lemma()
  ensures F<Cell>() < F<Cell>() + 1  // BUG: should complain that A must be (!new)
{
  // assert F<Cell>() < F<Cell>() + 1;
}

Command to run and resulting output

% dafny verify test.dfy

Dafny program verifier finished with 1 verified, 0 errors

What happened?

The type parameter of function F is declared as A(!new), which restricts it to types that do not contain references. Thus, the call F<Cell>() should be flagged as illegal, but it isn't.

Curiously, Dafny does flag the assertion, if uncommented, as illegal. So, it seems this check is just missing in the postcondition (or perhaps in specifications in general).

Here is another test example:

codatatype InfiniteTree<!A> = Node(value: int, next: A -> InfiniteTree)

greatest predicate Bisimilar<A(!new)>(t: InfiniteTree, u: InfiniteTree) {
  && t.value == u.value
  && forall a: A :: Bisimilar(t.next(a), u.next(a))
}

greatest lemma SelfSimilar<A>(t: InfiniteTree<A>)
  ensures Bisimilar<A>(t, t) // BUG: should complain that A must be (!new)
{
}

class Class { }

lemma SelfSimilarForClass(t: InfiniteTree<Class>)
  ensures Bisimilar<Class>(t, t) // BUG: should complain that A must be (!new)
{
  SelfSimilar<Class>(t);
}

lemma SelfSimilarForClassHash(o: ORDINAL, t: InfiniteTree<Class>)
  ensures Bisimilar#<Class>[o](t, t) // BUG: should complain that A must be (!new)
{
  SelfSimilar#<Class>[o](t);
}

What type of operating system are you experiencing the problem on?

Mac

@RustanLeino RustanLeino added kind: bug Crashes, unsoundness, incorrect output, etc. If possible, add a `part:` label part: resolver Resolution and typechecking labels Jan 2, 2024
@RustanLeino RustanLeino self-assigned this Jan 2, 2024
RustanLeino added a commit to RustanLeino/dafny that referenced this issue Jan 3, 2024
RustanLeino added a commit that referenced this issue Jan 22, 2024
…ult expressions (#4928)

This PR adds checks for correct instantiations of type parameters that
were previously missing. Previously, these checks were only done in
non-ghost expressions (historically, it seems the code that performs
these checks was designed for checking `(==)`, which applies only in
ghost expressions). This PR adds the checks also specifications (which
are ghost) and default expressions for parameters).

The new test file `git-issue-4926.dfy` reports 38 errors, whereas before
this PR, Dafny reported only 8.

It also extracts the code for these checks into a separate file,
`TypeCharacteristicChecker.cs` (in addition to the existing file
`CheckTypeCharacteristics_Visitor`).

Fixes #4926


<small>By submitting this pull request, I confirm that my contribution
is made under the terms of the [MIT
license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>

---------

Co-authored-by: Stefan Zetzsche <120379523+stefan-aws@users.noreply.github.com>
@RustanLeino
Copy link
Collaborator Author

For the record, here's an example that (before the bug fix) gave a surprising verification:

predicate True<A>(a: A) {
  true
}

ghost predicate TypeIsEmpty<A(!new)>() {
  !exists a: A :: True(a)
}

class Cell { }

method Test() returns (c: Cell)
  requires TypeIsEmpty<Cell>()
  ensures TypeIsEmpty<Cell>()
{
  c := new Cell;
}

method False()
  requires TypeIsEmpty<Cell>()
  ensures false
{
  var c := Test();
  assert True(c);
}

Method False() is able to prove false as a postcondition, because TypeIsEmpty has an empty reads clause, yet it is affected by the new allocation. If it were possible to establish the precondition of False() from nothing (which it isn't, since Dafny never promises that there aren't any instances of a class that a program can create instances of), then one would be able to prove false from nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: bug Crashes, unsoundness, incorrect output, etc. If possible, add a `part:` label part: resolver Resolution and typechecking
Projects
None yet
1 participant