-
Notifications
You must be signed in to change notification settings - Fork 256
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
Unable to reason about types that extends a non-ref trait #4973
Comments
I think it should be expected. |
I agree with @MikaelMayer. Here is some code to support that argument. To try this, use abstract module M {
trait Object {}
type A extends Object {}
type B extends Object {}
//lemma test(x: Object)
// ensures x is A ==> !(x is B)
}
module M0 refines M {
// Since A and B are opaque types in M, they may refer to the same type
type A = C
type B = C
trait C extends Object { }
datatype D extends C = D
lemma CounterExample() returns (x: Object)
ensures x is A && x is B
{
x := D;
var a: A := D;
var b: B := D;
assert a == x == b;
}
}
module M1 refines M {
// Here's a different way to show the counterexample. Here, A and B remain
// distinct types, but they are both extended by another type.
type A = AA
type B = BB
trait AA extends Object { }
trait BB extends Object { }
datatype D extends AA, BB = D
lemma CounterExample() returns (x: Object)
ensures x is A && x is B
{
x := D;
var a: A := D;
var b: B := D;
assert a == x == b;
}
} |
Reopening this just because while the counterexamples above are true given the lack of context in the original report, with more context to exclude those counterexamples it may be reasonable to expect Dafny to be able to prove the lemma. @txiang61 can you provide some of that context? |
Thanks for the explanation! I have some functions that does a subtype check and returns a value based on what the type is. Here is a simplified version of what I was trying to prove.
Just noticed that it doesn't seem to work with
I'm ok with just listing the relationships as axioms. It does gets long as the hierarchy expands and easy to make mistakes. Just wondering if there is a better way. |
That's indeed a must have. For now, you can do the proof like this: lemma test(x: Object)
ensures x is A ==> !(x is B)
{
if x is A {
var a: A :| a == x;
if x is B {
var b: B :| b == x;
assert false;
}
}
} |
Feel free to close this issue if your need has been resolved. |
The proof above no longer works for me using the latest Dafny commit (
|
Here's a slightly shorter proof, but the lemma still requires a quadratic number of postconditions: trait Object {
ghost function TypeId(): string
}
datatype A extends Object = A() {
ghost function TypeId(): string { "A" }
}
datatype B extends Object = B() {
ghost function TypeId(): string { "B" }
}
lemma DisjointAB(x: Object)
ensures !(x is A && x is B)
{
var _ := x.TypeId();
}
method convert(v: Object) returns (res: nat)
ensures v is B ==> res == 1
{
DisjointAB(v);
if v is A {
return 0;
} else if v is B {
return 1;
}
return 0;
} |
Could the postcondition on the lemma be something like ensures multiset{x is A, x is B, x is C}[true] == 1 , so it's linear in the number of types? @dschoepe is there a feature request remaining in this issue? |
With the workaround you suggested it's not a big issue, but I would say it'd still be a nicer user experience to have Dafny prove this on its own without these extra lemmas and |
Could you be more explicit about what you want it to prove without help? Sorry if I'm a little slow to understand |
Dafny version
4.4.0
Code to produce this issue
Command to run and resulting output
What happened?
It makes sense if both
A
andB
are trait, but fortype
I think it should be able to reason about it. IfA
andB
are classes, then the lemma can be proven.What type of operating system are you experiencing the problem on?
Mac
The text was updated successfully, but these errors were encountered: