I've managed to boil this down to the following test case but I'm wondering whether this is a limitation of the static checker in C# code contracts or something I'm missing. When I attempt to prove a contract using one style of code it throws an invariant unproven warning, yet (what I think is) an equivalent way of proving it works just fine.
Initially I thought this might be because I wasn't using an object with Pure properties (and therefore the code contracts couldn't assess whether the properties were deterministic) but creating a Pure wrapper around the object (happens to be Nullable<Int64>) didn't help.
Is there a difference between the first and third test cases, or am I correct in believing they are equivalent and it's just that the static checker can't evaluate the third case correctly?
//Works
private Int64? _violations = null;
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(CheckIsValid(_violations));
}
[Pure]
public static Boolean CheckIsValid(Int64? value)
{
return (value.HasValue ? value.Value >= 0 : true);
}
public Class1(Int64 violations)
{
Contract.Requires(violations >= 0);
Contract.Ensures(CheckIsValid(_violations));
_violations = violations;
}
//Doesn't work, not provably deterministic
private Int64? _violations = null;
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_violations.HasValue ? _violations.Value >= 0 : true);
}
public Class1(Int64 violations)
{
Contract.Requires(violations >= 0);
Contract.Ensures(_violations.HasValue ? _violations.Value >= 0 : true);
_violations = violations;
}
//Also doesn't work, even though it's provably deterministic
private PureNullableInt64 _violations = null; //A wrapper class around Int64? with [Pure] getters
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(_violations.HasValue ? _violations.Value >= 0 : true);
}
public Class1(Int64 violations)
{
Contract.Requires(violations >= 0);
Contract.Ensures(_violations.HasValue ? _violations.Value >= 0 : true);
_violations = violations;
}