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

feat: Generate a warning when 'old' has no effect #2610

Merged
merged 27 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0881783
snapshot
RustanLeino Aug 15, 2022
a341eca
Enhance two-state detection in resolver
RustanLeino Aug 17, 2022
c35603d
chore: Improve code to use modern C#
RustanLeino Aug 17, 2022
b50a6f8
fix: Use old heap in StmtExpr inside old
RustanLeino Aug 17, 2022
2dae005
fix: Check well-definedness of forall-ensures
RustanLeino Aug 17, 2022
ad59a9c
Update PR number in release notes
RustanLeino Aug 17, 2022
6f25adb
Merge branch 'master' into issue-2605
RustanLeino Aug 17, 2022
8a3949d
Merge branch 'master' into issue-2597
RustanLeino Aug 17, 2022
9127e05
Merge branch 'issue-2605' into issue-2597
RustanLeino Aug 17, 2022
d819bf1
Add test, now that 2605 is fixed
RustanLeino Aug 17, 2022
5395c68
Add release notes
RustanLeino Aug 17, 2022
5da653f
Update tests
RustanLeino Aug 17, 2022
e329d6a
Adjusts tests and answers
RustanLeino Aug 17, 2022
1d6b5f7
Add method to iterate over all expressions, even those in substatements
RustanLeino Aug 17, 2022
0434f90
Update concurrency tests
RustanLeino Aug 17, 2022
3216743
Update release notes
RustanLeino Aug 17, 2022
f4f26b6
Update release notes
RustanLeino Aug 17, 2022
439bd1e
Merge branch 'issue-2597' into issue-1989
RustanLeino Aug 17, 2022
3d5f5fb
Merge branch 'master' into issue-1989
RustanLeino Aug 24, 2022
5651f86
Add .expect file
RustanLeino Aug 24, 2022
db755a2
Merge branch 'master' into issue-1989
RustanLeino Aug 25, 2022
97cfb00
Merge branch 'master' into issue-1989
RustanLeino Aug 25, 2022
c3f6ebb
Merge branch 'master' into issue-1989
keyboardDrummer Aug 30, 2022
bfc3d61
Merge branch 'master' into issue-1989
RustanLeino Sep 1, 2022
a526739
Rename Linter to something more specific
RustanLeino Sep 1, 2022
2f75116
Merge branch 'master' into issue-1989
RustanLeino Sep 1, 2022
8b88899
Merge branch 'master' into issue-1989
keyboardDrummer Sep 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- fix: Missing related position in failing precondition (https://github.com/dafny-lang/dafny/pull/2658)
- fix: No more IDE crashing on the elephant operator (https://github.com/dafny-lang/dafny/pull/2668)
- feat: generate warning when 'old' has no effect

# 3.8.1

Expand All @@ -15,7 +16,6 @@
- fix: Better messages on hovering failing postconditions in IDE (https://github.com/dafny-lang/dafny/pull/2654)
- fix: Better error reporting on counter-examples if an option is not provided (https://github.com/dafny-lang/dafny/pull/2650)


# 3.8.0

- fix: Use the right bitvector comparison in decrease checks
Expand Down
20 changes: 19 additions & 1 deletion Source/Dafny/AST/DafnyAst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6723,6 +6723,24 @@ public Statement(IToken tok, IToken endTok)
Contract.Requires(endTok != null);
}

/// <summary>
/// Returns the non-null expressions of this statement proper (that is, do not include the expressions of substatements).
/// Filters all sub expressions that are not part of specifications
/// </summary>
public IEnumerable<Expression> SubExpressionsIncludingTransitiveSubStatements {
get {
foreach (var e in SubExpressions) {
yield return e;
}

foreach (var s in SubStatements) {
foreach (var e in s.SubExpressionsIncludingTransitiveSubStatements) {
yield return e;
}
}
}
}

/// <summary>
/// Returns the non-null substatements of the Statements.
/// </summary>
Expand Down Expand Up @@ -8759,7 +8777,7 @@ public TryRecoverStatement(Statement tryBody, IVariable haltMessageVar, Statemen
// ------------------------------------------------------------------------------------------------------

public abstract class TokenWrapper : IToken {
protected readonly IToken WrappedToken;
public readonly IToken WrappedToken;
protected TokenWrapper(IToken wrappedToken) {
Contract.Requires(wrappedToken != null);
WrappedToken = wrappedToken;
Expand Down
18 changes: 13 additions & 5 deletions Source/Dafny/AST/FreeVariablesUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,20 @@ public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs) {
bool dontCare0 = false, dontCare1 = false;
Type dontCareT = null;
var dontCareHeapAt = new HashSet<Label>();
ComputeFreeVariables(expr, fvs, ref dontCare0, ref dontCare1, dontCareHeapAt, ref dontCareT);
ComputeFreeVariables(expr, fvs, ref dontCare0, ref dontCare1, dontCareHeapAt, ref dontCareT, false);
}
public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap) {
public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap, bool includeStatements = false) {
Contract.Requires(expr != null);
Contract.Requires(fvs != null);
bool dontCare1 = false;
Type dontCareT = null;
var dontCareHeapAt = new HashSet<Label>();
ComputeFreeVariables(expr, fvs, ref usesHeap, ref dontCare1, dontCareHeapAt, ref dontCareT);
ComputeFreeVariables(expr, fvs, ref usesHeap, ref dontCare1, dontCareHeapAt, ref dontCareT, includeStatements);
}
public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap, ref bool usesOldHeap, ISet<Label> freeHeapAtVariables, ref Type usesThis) {
public static void ComputeFreeVariables(Expression expr,
ISet<IVariable> fvs,
ref bool usesHeap, ref bool usesOldHeap, ISet<Label> freeHeapAtVariables, ref Type usesThis,
bool includeStatements) {
Contract.Requires(expr != null);

if (expr is ThisExpr) {
Expand Down Expand Up @@ -113,8 +116,13 @@ public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, re
// visit subexpressions
bool uHeap = false, uOldHeap = false;
Type uThis = null;
if (expr is StmtExpr stmtExpr && includeStatements) {
foreach (var subExpression in stmtExpr.S.SubExpressionsIncludingTransitiveSubStatements) {
ComputeFreeVariables(subExpression, fvs, ref uHeap, ref uOldHeap, freeHeapAtVariables, ref uThis, includeStatements);
}
}
foreach (var subExpression in expr.SubExpressions) {
ComputeFreeVariables(subExpression, fvs, ref uHeap, ref uOldHeap, freeHeapAtVariables, ref uThis);
ComputeFreeVariables(subExpression, fvs, ref uHeap, ref uOldHeap, freeHeapAtVariables, ref uThis, includeStatements);
}
Contract.Assert(usesThis == null || uThis == null || usesThis.Equals(uThis));
usesThis = usesThis ?? uThis;
Expand Down
16 changes: 10 additions & 6 deletions Source/Dafny/Resolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ public void ResolveProgram(Program prog) {
rewriters.Add(new ConstructorWarning(reporter));
}

rewriters.Add(new UselessOldLinter(reporter));

foreach (var plugin in DafnyOptions.O.Plugins) {
rewriters.AddRange(plugin.GetRewriters(reporter));
}
Expand Down Expand Up @@ -10622,6 +10624,8 @@ void ResolveIterator(IteratorDecl iter) {
void CreateIteratorMethodSpecs(IteratorDecl iter) {
Contract.Requires(iter != null);

var tok = new AutoGeneratedToken(iter.tok);
Copy link
Member

@keyboardDrummer keyboardDrummer Aug 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we run 'the old has no effect' detection after we generate the iterator method specs? This works as well, but I'm curious what the best ordering of operations is. Maybe CreateIteratorMethodSpecs should not be part of the main resolution phase, but instead be part of the code-gen phase?

Can FreeVariableUtil.ComputeFreeVariables not be called before resolution? Maybe we should specify that in a comment on the before.

Side note: the AutoGeneratedToken concept seems strange to me. In generated code I wouldn't expect warnings/errors, and I wouldn't expect any non-nullish tokens there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linter is run after resolution. At that time (and not before that time), we have information about heap usage and variable definitions. For example, we know whether s[i] is referring to a sequence element or an array element. The free-variable machinery already has the ability to detect heap usage, so it made sense to call it from the linter.

There are a number of desugaring tasks (match, datatype update, iterators, ...) that are being done quite early. Creating new AST nodes is easier pre-resolution, because then the resolution pass will fill in type information. To my taste, some of that desugaring is done too early, or perhaps shouldn't be done at all. It would be good to have a discussion and redesign of all of that sometime. But for iterators, the desugaring does need to be done early, because the iterator desugaring introduces names that the program is allowed to call. So, this means iterator desugaring is necessarily done before the linter runs.

One could consider making the iterator desugaring more clever, so that it never generates useless old expressions. But this is difficult to determine before resolution (cf. my s[i] example above).

Therefore, to avoid linter warnings from such generated code, we need some way to keep track of which expressions have been automatically generated. We already had a mechanism for this, which is to put some information into the tokens. This is not perfect, and I'm not sure that we're using nested token wrappers correctly. For linter warnings, any such imperfections seem okay, since at worst we'd generate bad warnings or omit some warnings.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info. This approach seems good :)


// ---------- here comes the constructor ----------
// same requires clause as the iterator itself
iter.Member_Init.Req.AddRange(iter.Requires);
Expand Down Expand Up @@ -10653,7 +10657,7 @@ void CreateIteratorMethodSpecs(IteratorDecl iter) {
}
ens.Add(new AttributedExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_reads"),
new OldExpr(iter.tok, frameSet))));
new OldExpr(tok, frameSet))));
// ensures this._modifies == old(ModifiesClause);
modSetSingletons = new List<Expression>();
frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons);
Expand All @@ -10668,7 +10672,7 @@ void CreateIteratorMethodSpecs(IteratorDecl iter) {
}
ens.Add(new AttributedExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_modifies"),
new OldExpr(iter.tok, frameSet))));
new OldExpr(tok, frameSet))));
// ensures this._new == {};
ens.Add(new AttributedExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_new"),
Expand All @@ -10679,7 +10683,7 @@ void CreateIteratorMethodSpecs(IteratorDecl iter) {
var p = iter.Decreases.Expressions[i];
ens.Add(new AttributedExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), iter.DecreasesFields[i].Name),
new OldExpr(iter.tok, p))));
new OldExpr(tok, p))));
}

// ---------- here comes predicate Valid() ----------
Expand All @@ -10705,7 +10709,7 @@ void CreateIteratorMethodSpecs(IteratorDecl iter) {
ens.Add(new AttributedExpression(new FreshExpr(iter.tok,
new BinaryExpr(iter.tok, BinaryExpr.Opcode.Sub,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_new"),
new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_new"))))));
new OldExpr(tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_new"))))));
// ensures null !in _new
ens.Add(new AttributedExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.NotIn,
new LiteralExpr(iter.tok),
Expand All @@ -10722,9 +10726,9 @@ void CreateIteratorMethodSpecs(IteratorDecl iter) {
var ys = iter.OutsHistoryFields[i];
var ite = new ITEExpr(iter.tok, false, new IdentifierExpr(iter.tok, "more"),
new BinaryExpr(iter.tok, BinaryExpr.Opcode.Add,
new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)),
new OldExpr(tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)),
new SeqDisplayExpr(iter.tok, new List<Expression>() { new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), y.Name) })),
new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)));
new OldExpr(tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)));
var eq = new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name), ite);
ens.Add(new AttributedExpression(eq));
}
Expand Down
10 changes: 10 additions & 0 deletions Source/Dafny/Rewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ public AutoGeneratedToken(IToken wrappedToken)
: base(wrappedToken) {
Contract.Requires(wrappedToken != null);
}

public static bool Is(IToken tok) {
while (tok is TokenWrapper w) {
if (w is AutoGeneratedToken) {
return true;
}
tok = w.WrappedToken;
}
return false;
}
}

public class TriggerGeneratingRewriter : IRewriter {
Expand Down
2 changes: 1 addition & 1 deletion Source/Dafny/Triggers/TriggerUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ internal static IEnumerable<Expression> MaybeWrapInOld(Expression expr, HashSet<
Contract.Requires(wrap == null || wrap.Count != 0);
if (wrap != null && !(expr is NameSegment) && !(expr is IdentifierExpr)) {
foreach (var w in wrap) {
var newExpr = new OldExpr(expr.tok, expr, w.At) { AtLabel = w.AtLabel };
var newExpr = new OldExpr(new AutoGeneratedToken(expr.tok), expr, w.At) { AtLabel = w.AtLabel };
newExpr.Type = expr.Type;
yield return newExpr;
}
Expand Down
51 changes: 51 additions & 0 deletions Source/Dafny/UselessOldLinter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
// Copyright by the contributors to the Dafny Project
// SPDX-License-Identifier: MIT
//
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using System.Reactive;

namespace Microsoft.Dafny {

public class UselessOldLinter : IRewriter {
internal override void PostResolve(Program program) {
base.PostResolve(program);
foreach (var moduleDefinition in program.Modules()) {
foreach (var topLevelDecl in moduleDefinition.TopLevelDecls.OfType<TopLevelDeclWithMembers>()) {
foreach (var callable in topLevelDecl.Members.OfType<ICallable>()) {
var visitor = new UselessOldLinterVisitor(this.Reporter);
visitor.Visit(callable, Unit.Default);
}
}
}
}

public UselessOldLinter(ErrorReporter reporter) : base(reporter) {
}
}

class UselessOldLinterVisitor : TopDownVisitor<Unit> {
private readonly ErrorReporter reporter;

public UselessOldLinterVisitor(ErrorReporter reporter) {
this.reporter = reporter;
}

protected override bool VisitOneExpr(Expression expr, ref Unit st) {
if (expr is OldExpr oldExpr && !AutoGeneratedToken.Is(oldExpr.tok)) {
var fvs = new HashSet<IVariable>();
var usesHeap = false;
FreeVariablesUtil.ComputeFreeVariables(oldExpr.E, fvs, ref usesHeap, true);
if (!usesHeap) {
this.reporter.Warning(MessageSource.Rewriter, oldExpr.tok,
$"Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect");
}
}
return base.VisitOneExpr(expr, ref st);
}
}
}
6 changes: 3 additions & 3 deletions Source/Dafny/Verifier/Translator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1968,7 +1968,7 @@ void AddFunctionAxiom(Bpl.Function boogieFunction, Function f, Expression body)
bool dontCare0 = false, dontCare1 = false;
var dontCareHeapAt = new HashSet<Label>();
foreach (var e in f.Decreases.Expressions) {
FreeVariablesUtil.ComputeFreeVariables(e, FVs, ref dontCare0, ref dontCare1, dontCareHeapAt, ref usesThis);
FreeVariablesUtil.ComputeFreeVariables(e, FVs, ref dontCare0, ref dontCare1, dontCareHeapAt, ref usesThis, false);
}

var allFormals = new List<Formal>();
Expand Down Expand Up @@ -9129,7 +9129,7 @@ Expression LetDesugaring(LetExpr e) {
bool usesHeap = false, usesOldHeap = false;
var FVsHeapAt = new HashSet<Label>();
Type usesThis = null;
FreeVariablesUtil.ComputeFreeVariables(e.RHSs[0], FVs, ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis);
FreeVariablesUtil.ComputeFreeVariables(e.RHSs[0], FVs, ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis, false);
var FTVs = new HashSet<TypeParameter>();
foreach (var bv in e.BoundVars) {
FVs.Remove(bv);
Expand Down Expand Up @@ -10566,7 +10566,7 @@ public static bool UsesHeap(Expression expr) {
bool usesHeap = false, usesOldHeap = false;
var FVsHeapAt = new HashSet<Label>();
Type usesThis = null;
FreeVariablesUtil.ComputeFreeVariables(expr, new HashSet<IVariable>(), ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis);
FreeVariablesUtil.ComputeFreeVariables(expr, new HashSet<IVariable>(), ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis, false);
return usesHeap || usesOldHeap || FVsHeapAt.Count != 0;
}

Expand Down
1 change: 0 additions & 1 deletion Test/VSComp2010/Problem4-Queens.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ method SearchAux(N: int, boardSoFar: seq<int>) returns (success: bool, newBoard:
boardSoFar <= B
==>
(exists p :: 0 <= p && p < N && !IsConsistent(B, p)));
ensures (forall B, p :: IsConsistent(B, p) <==> old(IsConsistent(B, p)));
decreases N - |boardSoFar|;
{
var pos := |boardSoFar|;
Expand Down
1 change: 1 addition & 0 deletions Test/allocated1/dafny0/Simple.dfy.expect
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,6 @@ module B refines A {
...;
}
}
Simple.dfy(14,12): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect

Dafny program verifier did not attempt verification
2 changes: 2 additions & 0 deletions Test/allocated1/dafny0/SmallTests.dfy.expect
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SmallTests.dfy(548,4): Warning: /!\ No trigger covering all quantified variables found.
SmallTests.dfy(599,12): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect
SmallTests.dfy(34,11): Error: index out of range
SmallTests.dfy(65,35): Error: possible division by zero
SmallTests.dfy(66,50): Error: possible division by zero
Expand Down Expand Up @@ -52,5 +53,6 @@ SmallTests.dfy(716,8): Error: cannot establish the existence of LHS values that

Dafny program verifier finished with 51 verified, 46 errors
SmallTests.dfy.tmp.dprint.dfy(450,4): Warning: /!\ No trigger covering all quantified variables found.
SmallTests.dfy.tmp.dprint.dfy(740,12): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect

Dafny program verifier did not attempt verification
1 change: 1 addition & 0 deletions Test/allocated1/dafny0/Twostate-Verification.dfy.expect
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Twostate-Verification.dfy(34,13): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect
Twostate-Verification.dfy(39,26): Error: target object might not be allocated
Twostate-Verification.dfy(44,34): Error: target object might not be allocated
Twostate-Verification.dfy(60,26): Error: target object might not be allocated
Expand Down
7 changes: 2 additions & 5 deletions Test/concurrency/12-MutexLifetime-long.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,6 @@ trait OwnedObject extends Object {

twostate predicate unchangedNonvolatileFields() reads this {
&& old(owner) == owner
&& old(lifetime) == lifetime
&& unchangedNonvolatileUserFields()
}

Expand All @@ -454,7 +453,6 @@ trait OwnedObject extends Object {

twostate predicate localInv2() reads * {
&& (owner != null ==> localUserInv2())
&& old(lifetime) == lifetime
}

twostate predicate sequenceInv2() reads * {
Expand Down Expand Up @@ -690,16 +688,15 @@ class OutlivesClaim extends OwnedObject {
function objectUserFields(): set<Object> reads this { { source, target } }

twostate predicate unchangedNonvolatileUserFields() reads this {
&& old(target) == target
&& old(source) == source
true
}

predicate localUserInv() reads * {
&& objectGlobalBaseInv()
&& universe.outlives(target, source)
}
predicate userInv() reads * ensures userInv() ==> localUserInv() { localUserInv() }
twostate predicate localUserInv2() reads * { old(target) == target && old(source) == source }
twostate predicate localUserInv2() reads * { true }
twostate predicate userInv2() reads * ensures userInv2() ==> localUserInv2() { localUserInv2() }

twostate lemma sequenceAdmissibility(running: set<Thread>) requires goodPreAndLegalChangesSequence(running) ensures sequenceInv2() {}
Expand Down
7 changes: 2 additions & 5 deletions Test/concurrency/12-MutexLifetime-short.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,6 @@ trait OwnedObject extends Object {

twostate predicate unchangedNonvolatileFields() reads this {
&& old(owner) == owner
&& old(lifetime) == lifetime
&& unchangedNonvolatileUserFields()
}

Expand All @@ -453,7 +452,6 @@ trait OwnedObject extends Object {

twostate predicate localInv2() reads * {
&& (owner != null ==> localUserInv2())
&& old(lifetime) == lifetime
}

twostate predicate sequenceInv2() reads * {
Expand Down Expand Up @@ -689,16 +687,15 @@ class OutlivesClaim extends OwnedObject {
function objectUserFields(): set<Object> reads this { { source, target } }

twostate predicate unchangedNonvolatileUserFields() reads this {
&& old(target) == target
&& old(source) == source
true
}

predicate localUserInv() reads * {
&& objectGlobalBaseInv()
&& universe.outlives(target, source)
}
predicate userInv() reads * ensures userInv() ==> localUserInv() { localUserInv() }
twostate predicate localUserInv2() reads * { old(target) == target && old(source) == source }
twostate predicate localUserInv2() reads * { true }
twostate predicate userInv2() reads * ensures userInv2() ==> localUserInv2() { localUserInv2() }

twostate lemma sequenceAdmissibility(running: set<Thread>) requires goodPreAndLegalChangesSequence(running) ensures sequenceInv2() {}
Expand Down
2 changes: 1 addition & 1 deletion Test/concurrency/12-MutexLifetime-short.dfy.expect
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

Dafny program verifier finished with 204 verified, 0 errors
Dafny program verifier finished with 202 verified, 0 errors
2 changes: 2 additions & 0 deletions Test/dafny0/LabeledAsserts.dfy.expect
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
LabeledAsserts.dfy(63,9): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect
LabeledAsserts.dfy(63,30): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect
LabeledAsserts.dfy(25,11): Error: assertion might not hold
LabeledAsserts.dfy(27,18): Error: assertion might not hold
LabeledAsserts.dfy(28,18): Error: assertion might not hold
Expand Down
1 change: 1 addition & 0 deletions Test/dafny0/LabelsOldAt.dfy.expect
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
LabelsOldAt.dfy(160,13): Warning: Argument to 'old' does not dereference the mutable heap, so this use of 'old' has no effect
LabelsOldAt.dfy(34,13): Error: assertion might not hold
LabelsOldAt.dfy(56,11): Error: assertion might not hold
LabelsOldAt.dfy(78,13): Error: assertion might not hold
Expand Down
Loading