Open fhackett-ms opened 1 year ago
Unlike #725 (which is related), I believe this is not actually a bug, but just a very confusing error message.
In the test
module, the expression WF_vars(test1!Next)
breaks down like this:
WF_vars(test1!Next)
= ([]<>(~ENABLED <test1!Next>_vars)) \/ ([]<> <test1!Next>_vars)
= ... ENABLED (test1!Next /\ vars' /= vars) ...
= ... ENABLED ((i - 6)' = (i - 6) + 1 /\ i' /= i) ...
= ... ENABLED ((i' - 6) = (i - 6) + 1 /\ i' /= i) ...
= ... \E i_prime: (i_prime - 6) = (i - 6) + 1 /\ i_prime /= i ...
TLC is unable to evaluate that last expression; it isn't smart enough to synthesize a value for i_prime
that satisfies the formula. This is the exact same error you would see if you wrote e.g. Next == foo' = foo + 1
in module test
and disabled liveness checking entirely. foo' = foo+1
is the same as i' - 6 = (i - 6) + 1
, and TLC isn't smart enough to figure out what to do with that either.
Oh, and another quick (?) note:
Many other methods of referencing
i
work fine, including directly statingSpec1 == test1!Spec
Unfortunately, within the test
module, Spec1
and test1!Spec
are not actually equivalent! I left a comment about this here. Because they are different, you should not expect TLC to handle them the same way.
For comparison, within test
, the WF-expression within test1!Spec
desugars like this:
test1!Spec = ... WF_vars(Next) ... [with foo <- i - 6]
= ... ([]<>(~ENABLED <Next>_vars)) \/ ([]<> <Next>_vars) ... [with foo <- i - 6]
= ... ENABLED (Next /\ vars' /= vars) ... [with foo <- i - 6]
= ... ENABLED (foo' = foo + 1 /\ foo' /= foo) ... [with foo <- i - 6]
= ... \E foo_prime: foo_prime = foo + 1 /\ foo_prime /= foo ... [with foo <- i - 6]
= ... \E foo_prime: foo_prime = (i - 6) + 1 /\ foo_prime /= (i - 6)
This is a different expression, and it is one that TLC can handle, since there is a plain variable on the left side of the equals sign. So, it can synthesize values for foo_prime
that satisfy the expression.
Description
This example causes TLC to be unable to reference variable
i
, when using the refinement mappingfoo
. Many other methods of referencingi
work fine, including directly statingSpec1 == test1!Spec
, wheretest1!Spec
contains an equivalent definition, changing only how operators insidetest1
are referenced.I found this because my real spec requires me to specify a slightly different
Spec1
, relative totest1!Spec
, so I expanded and altered the definition in my top-level spec, causing the issue.With config:
Expected Behavior
(by changing to
Spec1 == test1!Spec
)Actual Behavior
Steps to Reproduce
See above.
Steps Taken to Fix
I minimized the issue, isolating what I think is the specific thing I did that caused it. Because of how specific the problem is and how every other variation works, I'm confident it's not an error in my TLA+ code.
Possible Fix
This is probably a bug in TLC's scope handling, an edge case that comes from mixing
!
and non-trivialINSTANCE
substitutions in an unexpected pattern.Your Environment
It is listed in the outputs I provide, as part of TLC's command-line output.