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

fix: For attributes, add missing resolution and fix pointless parsing #1900

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- fix: export-reveals of function-by-method now allows the function body to be ghost (https://github.com/dafny-lang/dafny/pull/1855)
- fix: Regain C# 7.3 compatibility of the compiled code. (https://github.com/dafny-lang/dafny/pull/1877)
- fix: The error "assertion violation" is replaced by the better wording "assertion might not hold". This indicates better that the verifier is unable to prove the assertion. (https://github.com/dafny-lang/dafny/pull/1862)
- fix: Resolve expressions in attributes in all specifications of functions and iterators. (https://github.com/dafny-lang/dafny/pull/1900)


# 3.4.2
Expand Down
10 changes: 5 additions & 5 deletions Source/Dafny/AST/DafnyAst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8042,7 +8042,7 @@ public override IEnumerable<Expression> NonSpecificationSubExpressions {
}
}

public class GuardedAlternative {
public class GuardedAlternative : IAttributeBearingDeclaration {
public readonly IToken Tok;
public readonly bool IsBindingGuard;
public readonly Expression Guard;
Expand Down Expand Up @@ -12478,7 +12478,7 @@ public NestedMatchCase(IToken tok, ExtendedPattern pat) {
}
}

public class NestedMatchCaseExpr : NestedMatchCase {
public class NestedMatchCaseExpr : NestedMatchCase, IAttributeBearingDeclaration {
public readonly Expression Body;
public Attributes Attributes;

Expand All @@ -12489,7 +12489,7 @@ public NestedMatchCaseExpr(IToken tok, ExtendedPattern pat, Expression body, Att
}
}

public class NestedMatchCaseStmt : NestedMatchCase {
public class NestedMatchCaseStmt : NestedMatchCase, IAttributeBearingDeclaration {
public readonly List<Statement> Body;
public Attributes Attributes;
public NestedMatchCaseStmt(IToken tok, ExtendedPattern pat, List<Statement> body) : base(tok, pat) {
Expand Down Expand Up @@ -12615,7 +12615,7 @@ public override IEnumerable<Expression> SubExpressions {
}
}

public class AttributedExpression {
public class AttributedExpression : IAttributeBearingDeclaration {
public readonly Expression E;
public readonly AssertLabel/*?*/ Label;

Expand Down Expand Up @@ -13035,7 +13035,7 @@ public ApplySuffix(IToken tok, IToken/*?*/ atLabel, Expression lhs, List<ActualB
}
}

public class Specification<T> where T : class {
public class Specification<T> : IAttributeBearingDeclaration where T : class {
public readonly List<T> Expressions;

[ContractInvariantMethod]
Expand Down
25 changes: 11 additions & 14 deletions Source/Dafny/Dafny.atg
Original file line number Diff line number Diff line change
Expand Up @@ -1831,10 +1831,8 @@ DecreasesClause<.List<Expression> decreases, ref Attributes attrs,
/*------------------------------------------------------------------------*/
ReadsClause<.List<FrameExpression/*!*/>/*!*/ reads,
bool allowLemma, bool allowLambda, bool allowWild.>
= "reads" (. Attributes attrs = null;
FrameExpression fe;
.)
{ Attribute<ref attrs> }
= "reads"
(. FrameExpression fe; .)
PossiblyWildFrameExpression<out fe, allowLemma, allowLambda, allowWild> (. reads.Add(fe); .)
{ "," PossiblyWildFrameExpression<out fe, allowLemma, allowLambda, allowWild> (. reads.Add(fe); .)
}
Expand Down Expand Up @@ -2134,6 +2132,7 @@ FunctionDecl<DeclModifierData dmod, out Function/*!*/ f>
List<AttributedExpression> ens = new List<AttributedExpression>();
List<FrameExpression> reads = new List<FrameExpression>();
List<Expression> decreases;
Attributes decAttrs = null;
Expression body = null;
bool isPredicate = false; bool isLeastPredicate = false; bool isGreatestPredicate = false;
IToken/*?*/ headToken = null; // used only for a basic "function" or "predicate"
Expand Down Expand Up @@ -2259,7 +2258,7 @@ FunctionDecl<DeclModifierData dmod, out Function/*!*/ f>
)

(. decreases = isLeastPredicate || isGreatestPredicate ? null : new List<Expression/*!*/>(); .)
FunctionSpec<reqs, reads, ens, decreases>
FunctionSpec<reqs, reads, ens, decreases, ref decAttrs>
(. IToken byMethodTok = null; BlockStmt byMethodBody = null; .)
[ FunctionBody<out body, out bodyStart, out bodyEnd, out byMethodTok, out byMethodBody> ]

Expand Down Expand Up @@ -2400,15 +2399,15 @@ FunctionDecl<DeclModifierData dmod, out Function/*!*/ f>
if (isTwoState && isPredicate) {
Contract.Assert(functionMethodToken == null && !dmod.IsGhost);
f = new TwoStatePredicate(tok, id.val, dmod.IsStatic, typeArgs, formals,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);
reqs, reads, ens, new Specification<Expression>(decreases, decAttrs), body, attrs, signatureEllipsis);
} else if (isTwoState) {
Contract.Assert(functionMethodToken == null && !dmod.IsGhost);
f = new TwoStateFunction(tok, id.val, dmod.IsStatic, typeArgs, formals, result, returnType,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);
reqs, reads, ens, new Specification<Expression>(decreases, decAttrs), body, attrs, signatureEllipsis);
} else if (isPredicate) {
Contract.Assert(functionMethodToken == null || !dmod.IsGhost);
f = new Predicate(tok, id.val, dmod.IsStatic, isGhost, typeArgs, formals,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited,
reqs, reads, ens, new Specification<Expression>(decreases, decAttrs), body, Predicate.BodyOriginKind.OriginalOrInherited,
byMethodTok, byMethodBody, attrs, signatureEllipsis);
} else if (isLeastPredicate) {
Contract.Assert(functionMethodToken == null && !dmod.IsGhost);
Expand All @@ -2422,7 +2421,7 @@ FunctionDecl<DeclModifierData dmod, out Function/*!*/ f>
Contract.Assert(functionMethodToken == null || !dmod.IsGhost);
f = new Function(tok, id.val, dmod.IsStatic, isGhost,
typeArgs, formals, result, returnType,
reqs, reads, ens, new Specification<Expression>(decreases, null), body,
reqs, reads, ens, new Specification<Expression>(decreases, decAttrs), body,
byMethodTok, byMethodBody,
attrs, signatureEllipsis);
}
Expand All @@ -2437,11 +2436,10 @@ FunctionDecl<DeclModifierData dmod, out Function/*!*/ f>
.

/*------------------------------------------------------------------------*/
FunctionSpec<.List<AttributedExpression/*!*/>/*!*/ reqs, List<FrameExpression/*!*/>/*!*/ reads, List<AttributedExpression/*!*/>/*!*/ ens, List<Expression/*!*/> decreases.>
FunctionSpec<.List<AttributedExpression> reqs, List<FrameExpression> reads, List<AttributedExpression> ens, List<Expression> decreases, ref Attributes decAttrs.>
= (. Contract.Requires(cce.NonNullElements(reqs));
Contract.Requires(cce.NonNullElements(reads));
Contract.Requires(decreases == null || cce.NonNullElements(decreases));
Attributes attrs = null;
.)
SYNC
{ RequiresClause<reqs, true>
Expand All @@ -2452,7 +2450,7 @@ FunctionSpec<.List<AttributedExpression/*!*/>/*!*/ reqs, List<FrameExpression/*!
decreases = new List<Expression/*!*/>();
}
.)
DecreasesClause<decreases, ref attrs, false, false>
DecreasesClause<decreases, ref decAttrs, false, false>
}
.

Expand Down Expand Up @@ -3999,8 +3997,7 @@ LambdaExpression<out Expression e, bool allowLemma, bool allowBitwiseOps>
// Coco says LambdaSpec is deletable. This is OK (it might be empty).
LambdaSpec<.ref List<FrameExpression> reads, ref Expression req.>
= { ReadsClause<reads, true, false, true>
| "requires" (. Attributes attrs = null; .)
{ Attribute<ref attrs> } (. Expression ee; .)
| "requires" (. Expression ee; .)
Expression<out ee, true, false> (. req = req == null ? ee : new BinaryExpr(req.tok, BinaryExpr.Opcode.And, req, ee); .)
}
.
Expand Down
30 changes: 19 additions & 11 deletions Source/Dafny/Resolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10118,6 +10118,7 @@ void ResolveFunction(Function f) {
}
ResolveParameterDefaultValues(f.Formals, f);
foreach (AttributedExpression e in f.Req) {
ResolveAttributes(e.Attributes, e, new ResolveOpts(f, f is TwoStateFunction));
Expression r = e.E;
ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction));
Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression
Expand All @@ -10132,14 +10133,15 @@ void ResolveFunction(Function f) {
scope.PushMarker();
scope.Push(f.Result.Name, f.Result); // function return only visible in post-conditions
}
ResolveAttributes(e.Attributes, e, new ResolveOpts(f, f is TwoStateFunction));
ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction, false, true, false)); // since this is a function, the postcondition is still a one-state predicate, unless it's a two-state function
Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(r, "Postcondition must be a boolean (got {0})");
if (f.Result != null) {
scope.PopMarker();
}
}
ResolveAttributes(f.Decreases.Attributes, null, new ResolveOpts(f, f is TwoStateFunction));
ResolveAttributes(f.Decreases.Attributes, f.Decreases, new ResolveOpts(f, f is TwoStateFunction));
foreach (Expression r in f.Decreases.Expressions) {
ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction));
// any type is fine
Expand Down Expand Up @@ -10281,13 +10283,13 @@ void ResolveMethod(Method m) {

// Start resolving specification...
foreach (AttributedExpression e in m.Req) {
ResolveAttributes(e.Attributes, null, new ResolveOpts(m, m is TwoStateLemma));
ResolveAttributes(e.Attributes, e, new ResolveOpts(m, m is TwoStateLemma));
ResolveExpression(e.E, new ResolveOpts(m, m is TwoStateLemma));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Precondition must be a boolean (got {0})");
}

ResolveAttributes(m.Mod.Attributes, null, new ResolveOpts(m, false));
ResolveAttributes(m.Mod.Attributes, m.Mod, new ResolveOpts(m, false));
foreach (FrameExpression fe in m.Mod.Expressions) {
ResolveFrameExpression(fe, FrameExpressionUse.Modifies, m);
if (m.IsLemmaLike) {
Expand All @@ -10296,7 +10298,7 @@ void ResolveMethod(Method m) {
DisallowNonGhostFieldSpecifiers(fe);
}
}
ResolveAttributes(m.Decreases.Attributes, null, new ResolveOpts(m, false));
ResolveAttributes(m.Decreases.Attributes, m.Decreases, new ResolveOpts(m, false));
foreach (Expression e in m.Decreases.Expressions) {
ResolveExpression(e, new ResolveOpts(m, m is TwoStateLemma));
// any type is fine
Expand Down Expand Up @@ -10324,7 +10326,7 @@ void ResolveMethod(Method m) {

// ... continue resolving specification
foreach (AttributedExpression e in m.Ens) {
ResolveAttributes(e.Attributes, null, new ResolveOpts(m, true));
ResolveAttributes(e.Attributes, e, new ResolveOpts(m, true));
ResolveExpression(e.E, new ResolveOpts(m, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Postcondition must be a boolean (got {0})");
Expand Down Expand Up @@ -10440,6 +10442,7 @@ void ResolveIterator(IteratorDecl iter) {
// we start with the decreases clause, because the _decreases<n> fields were only given type proxies before; we'll know
// the types only after resolving the decreases clause (and it may be that some of resolution has already seen uses of
// these fields; so, with no further ado, here we go
ResolveAttributes(iter.Decreases.Attributes, iter.Decreases, new ResolveOpts(iter, false));
Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count);
for (int i = 0; i < iter.Decreases.Expressions.Count; i++) {
var e = iter.Decreases.Expressions[i];
Expand All @@ -10452,10 +10455,12 @@ void ResolveIterator(IteratorDecl iter) {
foreach (FrameExpression fe in iter.Reads.Expressions) {
ResolveFrameExpression(fe, FrameExpressionUse.Reads, iter);
}
ResolveAttributes(iter.Modifies.Attributes, iter.Modifies, new ResolveOpts(iter, false));
foreach (FrameExpression fe in iter.Modifies.Expressions) {
ResolveFrameExpression(fe, FrameExpressionUse.Modifies, iter);
}
foreach (AttributedExpression e in iter.Requires) {
ResolveAttributes(e.Attributes, e, new ResolveOpts(iter, false));
ResolveExpression(e.E, new ResolveOpts(iter, false));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Precondition must be a boolean (got {0})");
Expand All @@ -10470,16 +10475,19 @@ void ResolveIterator(IteratorDecl iter) {
Contract.Assert(scope.AllowInstance);

foreach (AttributedExpression e in iter.YieldRequires) {
ResolveAttributes(e.Attributes, e, new ResolveOpts(iter, false));
ResolveExpression(e.E, new ResolveOpts(iter, false));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Yield precondition must be a boolean (got {0})");
}
foreach (AttributedExpression e in iter.YieldEnsures) {
ResolveAttributes(e.Attributes, e, new ResolveOpts(iter, true));
ResolveExpression(e.E, new ResolveOpts(iter, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Yield postcondition must be a boolean (got {0})");
}
foreach (AttributedExpression e in iter.Ensures) {
ResolveAttributes(e.Attributes, e, new ResolveOpts(iter, true));
ResolveExpression(e.E, new ResolveOpts(iter, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
ConstrainTypeExprBool(e.E, "Postcondition must be a boolean (got {0})");
Expand Down Expand Up @@ -11503,7 +11511,7 @@ public void ResolveStatement(Statement stmt, ICodeContext codeContext) {

} else if (stmt is ModifyStmt) {
var s = (ModifyStmt)stmt;
ResolveAttributes(s.Mod.Attributes, null, new ResolveOpts(codeContext, true));
ResolveAttributes(s.Mod.Attributes, s.Mod, new ResolveOpts(codeContext, true));
foreach (FrameExpression fe in s.Mod.Expressions) {
ResolveFrameExpression(fe, FrameExpressionUse.Modifies, codeContext);
}
Expand Down Expand Up @@ -11617,7 +11625,7 @@ private void ResolveLoopSpecificationComponents(List<AttributedExpression> invar
Contract.Requires(codeContext != null);

foreach (AttributedExpression inv in invariants) {
ResolveAttributes(inv.Attributes, null, new ResolveOpts(codeContext, true));
ResolveAttributes(inv.Attributes, inv, new ResolveOpts(codeContext, true));
ResolveExpression(inv.E, new ResolveOpts(codeContext, true));
Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression
if (fvs != null) {
Expand All @@ -11638,7 +11646,7 @@ private void ResolveLoopSpecificationComponents(List<AttributedExpression> invar
// any type is fine
}

ResolveAttributes(modifies.Attributes, null, new ResolveOpts(codeContext, true));
ResolveAttributes(modifies.Attributes, modifies, new ResolveOpts(codeContext, true));
if (modifies.Expressions != null) {
usesHeap = true; // bearing a modifies clause counts as using the heap
foreach (FrameExpression fe in modifies.Expressions) {
Expand Down Expand Up @@ -12722,7 +12730,7 @@ private void CheckLinearNestedMatchCase(Type type, NestedMatchCase mc, ResolveOp
private void CheckLinearNestedMatchExpr(Type dtd, NestedMatchExpr me, ResolveOpts opts) {
foreach (NestedMatchCaseExpr mc in me.Cases) {
scope.PushMarker();
ResolveAttributes(mc.Attributes, null, opts);
ResolveAttributes(mc.Attributes, mc, opts);
CheckLinearNestedMatchCase(dtd, mc, opts);
scope.PopMarker();
}
Expand All @@ -12731,7 +12739,7 @@ private void CheckLinearNestedMatchExpr(Type dtd, NestedMatchExpr me, ResolveOpt
private void CheckLinearNestedMatchStmt(Type dtd, NestedMatchStmt ms, ResolveOpts opts) {
foreach (NestedMatchCaseStmt mc in ms.Cases) {
scope.PushMarker();
ResolveAttributes(mc.Attributes, null, opts);
ResolveAttributes(mc.Attributes, mc, opts);
CheckLinearNestedMatchCase(dtd, mc, opts);
scope.PopMarker();
}
Expand Down Expand Up @@ -13381,7 +13389,7 @@ void ResolveAlternatives(List<GuardedAlternative> alternatives, AlternativeLoopS
ScopePushAndReport(scope, v, "bound-variable");
}
}
ResolveAttributes(alternative.Attributes, null, new ResolveOpts(codeContext, true));
ResolveAttributes(alternative.Attributes, alternative, new ResolveOpts(codeContext, true));
foreach (Statement ss in alternative.Body) {
ResolveStatementWithLabels(ss, codeContext);
}
Expand Down
Loading