Open jad-hamza opened 6 years ago
This should be resolved in #452 ?
Yes, at the moment #452 rejects all non strictly positive types. This can be relaxed by allowing them and then forcing the user to use explicit indices when folding/unfolding an A
(and only allow the generalization rules, without indices, for types that are strictly positive).
Here is another example, which doesn't use non-strict positive types but uses forall
and choose
:
import stainless.lang._
import stainless.proof._
object ForallBool {
def isEmpty[T]: Boolean = forall((x: T) => false)
case class A() {
require(isEmpty[A])
}
def isEmptyImpliesFalse(): Unit = {
require(isEmpty[A])
val a = A()
check(false)
()
} ensuring(_ => false)
def nonEmptyImpliesFalse(): Unit = {
require(!isEmpty[A])
val a = choose((x: A) => true)
assert(isEmpty[A])
check(false)
()
} ensuring(_ => false)
def proveFalse() = {
if (isEmpty[A]) isEmptyImpliesFalse()
else nonEmptyImpliesFalse()
assert(false)
}
}
The above snippet from @jad-hamza currently crashes in error: Well-formedness check failed after extraction
.
The fact that the above snipped failed well-formedness check seemed due to a type checker bug.
The unsoundess with choose from false can instead be seen in this slight variation of the code above, with refactored choose
:
import stainless.lang._
import stainless.proof._
object ForallBool {
def isEmpty[T]: Boolean = forall((x: T) => false)
case class A() {
require(isEmpty[A])
}
def isEmptyImpliesFalse(): Unit = {
require(isEmpty[A])
val a = A()
assert(false)
()
} ensuring((res:Unit) => false)
def getA: A = {
choose((x: A) => true)
}
def nonEmptyImpliesFalse(): Unit = {
require(!isEmpty[A])
val a = getA
assert(isEmpty[A])
assert(false)
()
}.ensuring((res:Unit) => false)
def proveFalse(): Unit = {
isEmptyImpliesFalse()
nonEmptyImpliesFalse()
assert(false)
()
}
}
with Version: 0.9.7-23-g98626b4 giving:
Forall.scala:19:5: warning: `choose` expressions may be unsafe due to difficulty in checking their realizability automatically
choose((x: A) => true)
^^^^^^^^^^^^^^^^^^^^^^
Starting verification...
Verified: 11 / 11
stainless summary
Forall.scala:7:14: ARequireForDefault class invariant valid from cache 0.1
Forall.scala:19:5: getA body assertion: Choose satisfiability valid from cache 0.0
isEmptyImpliesFalse body assertion valid from cache 0.0
Forall.scala:13:13: isEmptyImpliesFalse class invariant valid from cache 0.0
Forall.scala:14:5: isEmptyImpliesFalse postcondition trivial 0.0
nonEmptyImpliesFalse body assertion valid from cache 0.0
Forall.scala:25:5: nonEmptyImpliesFalse postcondition valid from cache 0.0
Forall.scala:25:12: nonEmptyImpliesFalse body assertion valid from cache 0.0
proveFalse body assertion valid from cache 0.0
Forall.scala:31:5: proveFalse precond. (call isEmptyImpliesFalse) valid from cache 0.0
Forall.scala:32:5: proveFalse precond. (call nonEmptyImpliesFalse) valid from cache 0.0
.............................................................................................................
total: 11 valid: 11 (10 from cache, 1 trivial) invalid: 0 unknown: 0 time: 0.08
We should make sure this is reportedly severely enough, check if the internal typechecking bug is desired or not, and then see if we emit warnings for quantifiers.
Just to make it clear: since contravariant types are not allowed currently, the soundness issue only that our report for realizability check is not severe enough.
Just to make it clear: since contravariant types are not allowed currently, the soundness issue only that our report for realizability check is not severe enough.
The above ForallBool
and the tests in false-valid
seem to be all related to missing a realizability check.
Stainless is able to derive false in that example adapted from http://vilhelms.github.io/posts/why-must-inductive-types-be-strictly-positive/ (original source: Inductively Defined Types (COLOG-88), also discussed in [Coq-Club] Positivity and Elimination Principle: https://sympa.inria.fr/sympa/arc/coq-club/2012-01/msg00087.html)
I don't really understand the example, but the ingredients needed in Stainless are: non-strict positive types for
A
, and quantifiers/impredicativity of Boolean inp0
PS: related to https://github.com/epfl-lara/stainless/issues/140
Edit: added an
assert
intheorem
to prevent theif then else
from being simplified away.