summaryrefslogtreecommitdiff
path: root/Source/Dafny
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Dafny')
-rw-r--r--Source/Dafny/BigIntegerParser.cs27
-rw-r--r--Source/Dafny/Cloner.cs255
-rw-r--r--Source/Dafny/Compiler.cs1606
-rw-r--r--Source/Dafny/Dafny.atg781
-rw-r--r--Source/Dafny/DafnyAst.cs1313
-rw-r--r--Source/Dafny/DafnyMain.cs20
-rw-r--r--Source/Dafny/DafnyOptions.cs170
-rw-r--r--Source/Dafny/DafnyPipeline.csproj20
-rw-r--r--Source/Dafny/Makefile4
-rw-r--r--Source/Dafny/Parser.cs2992
-rw-r--r--Source/Dafny/Printer.cs3963
-rw-r--r--Source/Dafny/RefinementTransformer.cs489
-rw-r--r--Source/Dafny/Reporting.cs160
-rw-r--r--Source/Dafny/Resolver.cs5244
-rw-r--r--Source/Dafny/Rewriter.cs910
-rw-r--r--Source/Dafny/Scanner.cs494
-rw-r--r--Source/Dafny/SccGraph.cs10
-rw-r--r--Source/Dafny/Translator.cs3631
-rw-r--r--Source/Dafny/Triggers/QuantifierSplitter.cs138
-rw-r--r--Source/Dafny/Triggers/QuantifiersCollection.cs211
-rw-r--r--Source/Dafny/Triggers/QuantifiersCollector.cs57
-rw-r--r--Source/Dafny/Triggers/TriggerExtensions.cs509
-rw-r--r--Source/Dafny/Triggers/TriggerUtils.cs265
-rw-r--r--Source/Dafny/Triggers/TriggersCollector.cs325
-rw-r--r--Source/Dafny/Util.cs157
25 files changed, 15360 insertions, 8391 deletions
diff --git a/Source/Dafny/BigIntegerParser.cs b/Source/Dafny/BigIntegerParser.cs
new file mode 100644
index 00000000..cd2cf314
--- /dev/null
+++ b/Source/Dafny/BigIntegerParser.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Numerics;
+using System.Globalization;
+
+namespace Microsoft.Dafny {
+ internal static class BigIntegerParser {
+ /// <summary>
+ /// Mono does not support the BigInteger.TryParse method. In practice,
+ /// we seldom actually need to parse huge integers, so it makes sense
+ /// to support most real-life cases by simply trying to parse using
+ /// Int64, and only falling back if needed.
+ /// </summary>
+ internal static BigInteger Parse(string str, NumberStyles style) {
+ UInt64 parsed;
+ if (UInt64.TryParse(str, style, NumberFormatInfo.CurrentInfo, out parsed)) {
+ return new BigInteger(parsed);
+ } else {
+ // Throws on Mono 3.2.8
+ return BigInteger.Parse(str, style);
+ }
+ }
+
+ internal static BigInteger Parse(string str) {
+ return BigIntegerParser.Parse(str, NumberStyles.Integer);
+ }
+ }
+} \ No newline at end of file
diff --git a/Source/Dafny/Cloner.cs b/Source/Dafny/Cloner.cs
index 9f83bf09..6d5e2961 100644
--- a/Source/Dafny/Cloner.cs
+++ b/Source/Dafny/Cloner.cs
@@ -17,12 +17,18 @@ namespace Microsoft.Dafny
if (m is DefaultModuleDecl) {
nw = new DefaultModuleDecl();
} else {
- nw = new ModuleDefinition(Tok(m.tok), name, m.IsAbstract, m.IsFacade, m.RefinementBaseName, m.Module, CloneAttributes(m.Attributes), true);
+ nw = new ModuleDefinition(Tok(m.tok), name, m.IsAbstract, m.IsFacade, m.IsExclusiveRefinement, m.RefinementBaseName, m.Module, CloneAttributes(m.Attributes), true);
}
foreach (var d in m.TopLevelDecls) {
nw.TopLevelDecls.Add(CloneDeclaration(d, nw));
}
- nw.RefinementBase = m.RefinementBase;
+ if (null != m.RefinementBase) {
+ nw.RefinementBase = m.RefinementBase;
+ }
+ if (null != m.RefinementBaseSig) {
+ nw.RefinementBaseSig = m.RefinementBaseSig;
+ }
+ nw.ClonedFrom = m;
nw.Height = m.Height;
return nw;
}
@@ -33,17 +39,17 @@ namespace Microsoft.Dafny
if (d is OpaqueTypeDecl) {
var dd = (OpaqueTypeDecl)d;
- return new OpaqueTypeDecl(Tok(dd.tok), dd.Name, m, dd.EqualitySupport, dd.TypeArgs.ConvertAll(CloneTypeParam), CloneAttributes(dd.Attributes));
+ return new OpaqueTypeDecl(Tok(dd.tok), dd.Name, m, dd.EqualitySupport, dd.TypeArgs.ConvertAll(CloneTypeParam), CloneAttributes(dd.Attributes), d);
} else if (d is TypeSynonymDecl) {
var dd = (TypeSynonymDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
- return new TypeSynonymDecl(Tok(dd.tok), dd.Name, tps, m, CloneType(dd.Rhs), CloneAttributes(dd.Attributes));
+ return new TypeSynonymDecl(Tok(dd.tok), dd.Name, tps, m, CloneType(dd.Rhs), CloneAttributes(dd.Attributes), dd);
} else if (d is NewtypeDecl) {
var dd = (NewtypeDecl)d;
if (dd.Var == null) {
- return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneType(dd.BaseType), CloneAttributes(dd.Attributes));
+ return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneType(dd.BaseType), CloneAttributes(dd.Attributes), dd);
} else {
- return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneBoundVar(dd.Var), CloneExpr(dd.Constraint), CloneAttributes(dd.Attributes));
+ return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneBoundVar(dd.Var), CloneExpr(dd.Constraint), CloneAttributes(dd.Attributes), dd);
}
} else if (d is TupleTypeDecl) {
var dd = (TupleTypeDecl)d;
@@ -52,13 +58,13 @@ namespace Microsoft.Dafny
var dd = (IndDatatypeDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var ctors = dd.Ctors.ConvertAll(CloneCtor);
- var dt = new IndDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes));
+ var dt = new IndDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes), dd);
return dt;
} else if (d is CoDatatypeDecl) {
var dd = (CoDatatypeDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var ctors = dd.Ctors.ConvertAll(CloneCtor);
- var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes));
+ var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes), dd);
return dt;
} else if (d is IteratorDecl) {
var dd = (IteratorDecl)d;
@@ -94,7 +100,7 @@ namespace Microsoft.Dafny
var dd = (TraitDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var mm = dd.Members.ConvertAll(CloneMember);
- var cl = new TraitDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes));
+ var cl = new TraitDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd);
return cl;
}
}
@@ -103,9 +109,9 @@ namespace Microsoft.Dafny
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var mm = dd.Members.ConvertAll(CloneMember);
if (d is DefaultClassDecl) {
- return new DefaultClassDecl(m, mm);
+ return new DefaultClassDecl(m, mm, ((DefaultClassDecl)d));
} else {
- return new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd.TraitsTyp.ConvertAll(CloneType));
+ return new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd.TraitsTyp.ConvertAll(CloneType), dd);
}
} else if (d is ModuleDecl) {
if (d is LiteralModuleDecl) {
@@ -123,6 +129,11 @@ namespace Microsoft.Dafny
abs.Signature = a.Signature;
abs.OriginalSignature = a.OriginalSignature;
return abs;
+ } else if (d is ModuleExportDecl) {
+ var a = (ModuleExportDecl)d;
+ var export = new ModuleExportDecl(a.tok, m, a.IsDefault, a.Exports, a.Extends);
+ export.Signature = a.Signature;
+ return export;
} else {
Contract.Assert(false); // unexpected declaration
return null; // to please compiler
@@ -134,11 +145,11 @@ namespace Microsoft.Dafny
}
public DatatypeCtor CloneCtor(DatatypeCtor ct) {
- return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes));
+ return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes), ct);
}
public TypeParameter CloneTypeParam(TypeParameter tp) {
- return new TypeParameter(Tok(tp.tok), tp.Name, tp.EqualitySupport);
+ return new TypeParameter(Tok(tp.tok), tp.Name, tp.EqualitySupport, tp);
}
public MemberDecl CloneMember(MemberDecl member) {
@@ -160,7 +171,7 @@ namespace Microsoft.Dafny
return t;
} else if (t is SetType) {
var tt = (SetType)t;
- return new SetType(CloneType(tt.Arg));
+ return new SetType(tt.Finite, CloneType(tt.Arg));
} else if (t is SeqType) {
var tt = (SeqType)t;
return new SeqType(CloneType(tt.Arg));
@@ -187,7 +198,7 @@ namespace Microsoft.Dafny
return new InferredTypeProxy();
} else if (t is OperationTypeProxy) {
var p = (OperationTypeProxy)t;
- return new OperationTypeProxy(p.AllowInts, p.AllowReals, p.AllowChar, p.AllowSeq, p.AllowSetVarieties);
+ return new OperationTypeProxy(p.AllowInts, p.AllowReals, p.AllowChar, p.AllowSeq, p.AllowSetVarieties, p.AllowISet);
} else if (t is ParamTypeProxy) {
return new ParamTypeProxy(CloneTypeParam(((ParamTypeProxy)t).orig));
} else {
@@ -225,6 +236,9 @@ namespace Microsoft.Dafny
public Attributes CloneAttributes(Attributes attrs) {
if (attrs == null) {
return null;
+ } else if (attrs.Name.StartsWith("_")) {
+ // skip this attribute, since it would have been produced during resolution
+ return CloneAttributes(attrs.Prev);
} else {
return new Attributes(attrs.Name, attrs.Args.ConvertAll(CloneExpr), CloneAttributes(attrs.Prev));
}
@@ -243,7 +257,7 @@ namespace Microsoft.Dafny
var e = (LiteralExpr)expr;
if (e is StaticReceiverExpr) {
var ee = (StaticReceiverExpr)e;
- return new StaticReceiverExpr(e.tok, CloneType(ee.UnresolvedType));
+ return new StaticReceiverExpr(e.tok, CloneType(ee.UnresolvedType), ee.IsImplicit);
} else if (e.Value == null) {
return new LiteralExpr(Tok(e.tok));
} else if (e.Value is bool) {
@@ -277,7 +291,7 @@ namespace Microsoft.Dafny
} else if (expr is DisplayExpression) {
DisplayExpression e = (DisplayExpression)expr;
if (expr is SetDisplayExpr) {
- return new SetDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));
+ return new SetDisplayExpr(Tok(e.tok), ((SetDisplayExpr)expr).Finite, e.Elements.ConvertAll(CloneExpr));
} else if (expr is MultiSetDisplayExpr) {
return new MultiSetDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));
} else {
@@ -294,15 +308,13 @@ namespace Microsoft.Dafny
return new MapDisplayExpr(Tok(expr.tok), e.Finite, pp);
} else if (expr is NameSegment) {
- var e = (NameSegment)expr;
- return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));
+ return CloneNameSegment(expr);
} else if (expr is ExprDotName) {
var e = (ExprDotName)expr;
return new ExprDotName(Tok(e.tok), CloneExpr(e.Lhs), e.SuffixName, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));
} else if (expr is ApplySuffix) {
- var e = (ApplySuffix)expr;
- return new ApplySuffix(Tok(e.tok), CloneExpr(e.Lhs), e.Args.ConvertAll(CloneExpr));
-
+ var e = (ApplySuffix) expr;
+ return CloneApplySuffix(e);
} else if (expr is MemberSelectExpr) {
var e = (MemberSelectExpr)expr;
return new MemberSelectExpr(Tok(e.tok), CloneExpr(e.Obj), e.MemberName);
@@ -319,6 +331,10 @@ namespace Microsoft.Dafny
var e = (SeqUpdateExpr)expr;
return new SeqUpdateExpr(Tok(e.tok), CloneExpr(e.Seq), CloneExpr(e.Index), CloneExpr(e.Value));
+ } else if (expr is DatatypeUpdateExpr) {
+ var e = (DatatypeUpdateExpr)expr;
+ return new DatatypeUpdateExpr(Tok(e.tok), CloneExpr(e.Root), e.Updates.ConvertAll(t => Tuple.Create(Tok(t.Item1), t.Item2, CloneExpr(t.Item3))));
+
} else if (expr is FunctionCallExpr) {
var e = (FunctionCallExpr)expr;
return new FunctionCallExpr(Tok(e.tok), e.Name, CloneExpr(e.Receiver), e.OpenParen == null ? null : Tok(e.OpenParen), e.Args.ConvertAll(CloneExpr));
@@ -385,7 +401,8 @@ namespace Microsoft.Dafny
return new LambdaExpr(tk, l.OneShot, bvs, range, l.Reads.ConvertAll(CloneFrameExpr), term);
} else {
Contract.Assert(e is SetComprehension);
- return new SetComprehension(tk, bvs, range, term, CloneAttributes(e.Attributes));
+ var tt = (SetComprehension)e;
+ return new SetComprehension(tk, tt.Finite, bvs, range, term, CloneAttributes(e.Attributes));
}
} else if (expr is WildcardExpr) {
@@ -411,7 +428,7 @@ namespace Microsoft.Dafny
} else if (expr is MatchExpr) {
var e = (MatchExpr)expr;
return new MatchExpr(Tok(e.tok), CloneExpr(e.Source),
- e.Cases.ConvertAll(c => new MatchCaseExpr(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body))), e.UsesOptionalBraces);
+ e.Cases.ConvertAll(CloneMatchCaseExpr), e.UsesOptionalBraces);
} else if (expr is NegationExpression) {
var e = (NegationExpression)expr;
@@ -422,6 +439,22 @@ namespace Microsoft.Dafny
}
}
+ public MatchCaseExpr CloneMatchCaseExpr(MatchCaseExpr c) {
+ Contract.Requires(c != null);
+ if (c.Arguments != null) {
+ Contract.Assert(c.CasePatterns == null);
+ return new MatchCaseExpr(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body));
+ } else {
+ Contract.Assert(c.Arguments == null);
+ Contract.Assert(c.CasePatterns != null);
+ return new MatchCaseExpr(Tok(c.tok), c.Id, c.CasePatterns.ConvertAll(CloneCasePattern), CloneExpr(c.Body));
+ }
+ }
+
+ public virtual Expression CloneApplySuffix(ApplySuffix e) {
+ return new ApplySuffix(Tok(e.tok), CloneExpr(e.Lhs), e.Args.ConvertAll(CloneExpr));
+ }
+
public virtual CasePattern CloneCasePattern(CasePattern pat) {
Contract.Requires(pat != null);
if (pat.Var != null) {
@@ -433,6 +466,11 @@ namespace Microsoft.Dafny
}
}
+ public virtual NameSegment CloneNameSegment(Expression expr) {
+ var e = (NameSegment)expr;
+ return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));
+ }
+
public virtual AssignmentRhs CloneRHS(AssignmentRhs rhs) {
AssignmentRhs c;
if (rhs is ExprRhs) {
@@ -505,7 +543,7 @@ namespace Microsoft.Dafny
} else if (stmt is IfStmt) {
var s = (IfStmt)stmt;
- r = new IfStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Guard), CloneBlockStmt(s.Thn), CloneStmt(s.Els));
+ r = new IfStmt(Tok(s.Tok), Tok(s.EndTok), s.IsExistentialGuard, CloneExpr(s.Guard), CloneBlockStmt(s.Thn), CloneStmt(s.Els));
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
@@ -522,15 +560,25 @@ namespace Microsoft.Dafny
} else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
r = new ForallStmt(Tok(s.Tok), Tok(s.EndTok), s.BoundVars.ConvertAll(CloneBoundVar), null, CloneExpr(s.Range), s.Ens.ConvertAll(CloneMayBeFreeExpr), CloneStmt(s.Body));
-
+ if (s.ForallExpressions != null) {
+ ((ForallStmt)r).ForallExpressions = s.ForallExpressions.ConvertAll(CloneExpr);
+ }
} else if (stmt is CalcStmt) {
- var s = (CalcStmt)stmt;
- r = new CalcStmt(Tok(s.Tok), Tok(s.EndTok), CloneCalcOp(s.Op), s.Lines.ConvertAll(CloneExpr), s.Hints.ConvertAll(CloneBlockStmt), s.StepOps.ConvertAll(CloneCalcOp), CloneCalcOp(s.ResultOp));
+ var s = (CalcStmt)stmt;
+ // calc statements have the unusual property that the last line is duplicated. If that is the case (which
+ // we expect it to be here), we share the clone of that line as well.
+ var lineCount = s.Lines.Count;
+ var lines = new List<Expression>(lineCount);
+ for (int i = 0; i < lineCount; i++) {
+ lines.Add(i == lineCount - 1 && 2 <= lineCount && s.Lines[i] == s.Lines[i - 1] ? lines[i - 1] : CloneExpr(s.Lines[i]));
+ }
+ Contract.Assert(lines.Count == lineCount);
+ r = new CalcStmt(Tok(s.Tok), Tok(s.EndTok), CloneCalcOp(s.Op), lines, s.Hints.ConvertAll(CloneBlockStmt), s.StepOps.ConvertAll(CloneCalcOp), CloneCalcOp(s.ResultOp), CloneAttributes(s.Attributes));
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
r = new MatchStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Source),
- s.Cases.ConvertAll(c => new MatchCaseStmt(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), c.Body.ConvertAll(CloneStmt))), s.UsesOptionalBraces);
+ s.Cases.ConvertAll(CloneMatchCaseStmt), s.UsesOptionalBraces);
} else if (stmt is AssignSuchThatStmt) {
var s = (AssignSuchThatStmt)stmt;
@@ -545,6 +593,10 @@ namespace Microsoft.Dafny
var lhss = s.Locals.ConvertAll(c => new LocalVariable(Tok(c.Tok), Tok(c.EndTok), c.Name, CloneType(c.OptionalType), c.IsGhost));
r = new VarDeclStmt(Tok(s.Tok), Tok(s.EndTok), lhss, (ConcreteUpdateStatement)CloneStmt(s.Update));
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt) stmt;
+ r = new LetStmt(Tok(s.Tok), Tok(s.EndTok), s.LHSs.ConvertAll(CloneCasePattern), s.RHSs.ConvertAll(CloneExpr));
+
} else if (stmt is ModifyStmt) {
var s = (ModifyStmt)stmt;
var mod = CloneSpecFrameExpr(s.Mod);
@@ -562,6 +614,18 @@ namespace Microsoft.Dafny
return r;
}
+ public MatchCaseStmt CloneMatchCaseStmt(MatchCaseStmt c) {
+ Contract.Requires(c != null);
+ if (c.Arguments != null) {
+ Contract.Assert(c.CasePatterns == null);
+ return new MatchCaseStmt(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), c.Body.ConvertAll(CloneStmt));
+ } else {
+ Contract.Assert(c.Arguments == null);
+ Contract.Assert(c.CasePatterns != null);
+ return new MatchCaseStmt(Tok(c.tok), c.Id, c.CasePatterns.ConvertAll(CloneCasePattern), c.Body.ConvertAll(CloneStmt));
+ }
+ }
+
public CalcStmt.CalcOp CloneCalcOp(CalcStmt.CalcOp op) {
if (op is CalcStmt.BinaryCalcOp) {
return new CalcStmt.BinaryCalcOp(((CalcStmt.BinaryCalcOp) op).Op);
@@ -585,7 +649,7 @@ namespace Microsoft.Dafny
}
public GuardedAlternative CloneGuardedAlternative(GuardedAlternative alt) {
- return new GuardedAlternative(Tok(alt.Tok), CloneExpr(alt.Guard), alt.Body.ConvertAll(CloneStmt));
+ return new GuardedAlternative(Tok(alt.Tok), alt.IsExistentialGuard, CloneExpr(alt.Guard), alt.Body.ConvertAll(CloneStmt));
}
public Function CloneFunction(Function f, string newName = null) {
@@ -603,16 +667,16 @@ namespace Microsoft.Dafny
if (f is Predicate) {
return new Predicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals,
- req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), null);
+ req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), null, f);
} else if (f is InductivePredicate) {
return new InductivePredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, tps, formals,
- req, reads, ens, body, CloneAttributes(f.Attributes), null);
+ req, reads, ens, body, CloneAttributes(f.Attributes), null, f);
} else if (f is CoPredicate) {
return new CoPredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, tps, formals,
- req, reads, ens, body, CloneAttributes(f.Attributes), null);
+ req, reads, ens, body, CloneAttributes(f.Attributes), null, f);
} else {
return new Function(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals, CloneType(f.ResultType),
- req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null);
+ req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null, f);
}
}
@@ -630,19 +694,19 @@ namespace Microsoft.Dafny
var body = CloneBlockStmt(m.Body);
if (m is Constructor) {
return new Constructor(Tok(m.tok), m.Name, tps, ins,
- req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m);
} else if (m is InductiveLemma) {
return new InductiveLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m);
} else if (m is CoLemma) {
return new CoLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m);
} else if (m is Lemma) {
return new Lemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m);
} else {
return new Method(Tok(m.tok), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m);
}
}
public virtual IToken Tok(IToken tok) {
@@ -668,21 +732,27 @@ namespace Microsoft.Dafny
abstract class FixpointCloner : Cloner
{
protected readonly Expression k;
- readonly Resolver resolver;
- readonly string suffix;
- protected FixpointCloner(Expression k, Resolver resolver)
+ protected readonly ErrorReporter reporter;
+ protected readonly string suffix;
+ protected FixpointCloner(Expression k, ErrorReporter reporter)
{
Contract.Requires(k != null);
- Contract.Requires(resolver != null);
+ Contract.Requires(reporter != null);
this.k = k;
- this.resolver = resolver;
+ this.reporter = reporter;
this.suffix = string.Format("#[{0}]", Printer.ExprToString(k));
}
- protected void ReportAdditionalInformation(IToken tok, string s)
- {
- Contract.Requires(tok != null);
- Contract.Requires(s != null);
- resolver.ReportAdditionalInformation(tok, s + suffix, s.Length);
+ protected Expression CloneCallAndAddK(FunctionCallExpr e) {
+ Contract.Requires(e != null);
+ var receiver = CloneExpr(e.Receiver);
+ var args = new List<Expression>();
+ args.Add(k);
+ foreach (var arg in e.Args) {
+ args.Add(CloneExpr(arg));
+ }
+ var fexp = new FunctionCallExpr(Tok(e.tok), e.Name + "#", receiver, e.OpenParen, args);
+ reporter.Info(MessageSource.Cloner, e.tok, e.Name + suffix);
+ return fexp;
}
}
@@ -693,17 +763,18 @@ namespace Microsoft.Dafny
/// precondition (resp. postcondition) of the inductive lemma's (resp. colemma's) corresponding prefix lemma.
/// It is assumed that the source expression has been resolved. Note, the "k" given to the constructor
/// is not cloned with each use; it is simply used as is.
+ /// The resulting expression needs to be resolved by the caller.
/// </summary>
class FixpointLemmaSpecificationSubstituter : FixpointCloner
{
readonly bool isCoContext;
readonly ISet<Expression> friendlyCalls;
- public FixpointLemmaSpecificationSubstituter(ISet<Expression> friendlyCalls, Expression k, Resolver resolver, bool isCoContext)
- : base(k, resolver)
+ public FixpointLemmaSpecificationSubstituter(ISet<Expression> friendlyCalls, Expression k, ErrorReporter reporter, bool isCoContext)
+ : base(k, reporter)
{
Contract.Requires(friendlyCalls != null);
Contract.Requires(k != null);
- Contract.Requires(resolver != null);
+ Contract.Requires(reporter != null);
this.isCoContext = isCoContext;
this.friendlyCalls = friendlyCalls;
}
@@ -716,15 +787,7 @@ namespace Microsoft.Dafny
} else if (expr is FunctionCallExpr) {
var e = (FunctionCallExpr)expr;
if (friendlyCalls.Contains(e)) {
- var receiver = CloneExpr(e.Receiver);
- var args = new List<Expression>();
- args.Add(k);
- foreach (var arg in e.Args) {
- args.Add(CloneExpr(arg));
- }
- var fexp = new FunctionCallExpr(Tok(e.tok), e.Name + "#", receiver, e.OpenParen, args);
- ReportAdditionalInformation(e.tok, e.Name);
- return fexp;
+ return CloneCallAndAddK(e);
}
} else if (expr is BinaryExpr && isCoContext) {
var e = (BinaryExpr)expr;
@@ -734,7 +797,7 @@ namespace Microsoft.Dafny
var B = CloneExpr(e.E1);
var teq = new TernaryExpr(Tok(e.tok), op, k, A, B);
var opString = op == TernaryExpr.Opcode.PrefixEqOp ? "==" : "!=";
- ReportAdditionalInformation(e.tok, opString);
+ reporter.Info(MessageSource.Cloner, e.tok, opString + suffix);
return teq;
}
}
@@ -763,19 +826,77 @@ namespace Microsoft.Dafny
}
/// <summary>
- /// The task of the FixpointLemmaBodyCloner is to fill in the implicit _k-1 arguments in recursive inductive/co-lemma calls.
+ /// The task of the FixpointLemmaBodyCloner is to fill in the implicit _k-1 arguments in recursive inductive/co-lemma calls
+ /// and in calls to the focal predicates.
/// The source statement and the given "k" are assumed to have been resolved.
/// </summary>
class FixpointLemmaBodyCloner : FixpointCloner
{
readonly FixpointLemma context;
- public FixpointLemmaBodyCloner(FixpointLemma context, Expression k, Resolver resolver)
- : base(k, resolver)
+ readonly ISet<FixpointPredicate> focalPredicates;
+ public FixpointLemmaBodyCloner(FixpointLemma context, Expression k, ISet<FixpointPredicate> focalPredicates, ErrorReporter reporter)
+ : base(k, reporter)
{
Contract.Requires(context != null);
Contract.Requires(k != null);
- Contract.Requires(resolver != null);
+ Contract.Requires(reporter != null);
this.context = context;
+ this.focalPredicates = focalPredicates;
+ }
+ public override Expression CloneExpr(Expression expr) {
+ if (DafnyOptions.O.RewriteFocalPredicates) {
+ if (expr is FunctionCallExpr) {
+ var e = (FunctionCallExpr)expr;
+#if DEBUG_PRINT
+ if (e.Function.Name.EndsWith("#") && Contract.Exists(focalPredicates, p => e.Function.Name == p.Name + "#")) {
+ Console.WriteLine("{0}({1},{2}): DEBUG: Possible opportunity to rely on new rewrite: {3}", e.tok.filename, e.tok.line, e.tok.col, Printer.ExprToString(e));
+ }
+#endif
+ // Note, we don't actually ever get here, because all calls will have been parsed as ApplySuffix.
+ // However, if something changes in the future (for example, some rewrite that changing an ApplySuffix
+ // to its resolved FunctionCallExpr), then we do want this code, so with the hope of preventing
+ // some error in the future, this case is included. (Of course, it is currently completely untested!)
+ var f = e.Function as FixpointPredicate;
+ if (f != null && focalPredicates.Contains(f)) {
+#if DEBUG_PRINT
+ var r = CloneCallAndAddK(e);
+ Console.WriteLine("{0}({1},{2}): DEBUG: Rewrote extreme predicate into prefix predicate: {3}", e.tok.filename, e.tok.line, e.tok.col, Printer.ExprToString(r));
+ return r;
+#else
+ return CloneCallAndAddK(e);
+#endif
+ }
+ } else if (expr is ApplySuffix) {
+ var apply = (ApplySuffix)expr;
+ if (!apply.WasResolved()) {
+ // Since we're assuming the enclosing statement to have been resolved, this ApplySuffix must
+ // be part of an ExprRhs that actually designates a method call. Such an ApplySuffix does
+ // not get listed as being resolved, but its components (like its .Lhs) are resolved.
+ var mse = (MemberSelectExpr)apply.Lhs.Resolved;
+ Contract.Assume(mse.Member is Method);
+ } else {
+ var fce = apply.Resolved as FunctionCallExpr;
+ if (fce != null) {
+#if DEBUG_PRINT
+ if (fce.Function.Name.EndsWith("#") && Contract.Exists(focalPredicates, p => fce.Function.Name == p.Name + "#")) {
+ Console.WriteLine("{0}({1},{2}): DEBUG: Possible opportunity to rely on new rewrite: {3}", fce.tok.filename, fce.tok.line, fce.tok.col, Printer.ExprToString(fce));
+ }
+#endif
+ var f = fce.Function as FixpointPredicate;
+ if (f != null && focalPredicates.Contains(f)) {
+#if DEBUG_PRINT
+ var r = CloneCallAndAddK(fce);
+ Console.WriteLine("{0}({1},{2}): DEBUG: Rewrote extreme predicate into prefix predicate: {3}", fce.tok.filename, fce.tok.line, fce.tok.col, Printer.ExprToString(r));
+ return r;
+#else
+ return CloneCallAndAddK(fce);
+#endif
+ }
+ }
+ }
+ }
+ }
+ return base.CloneExpr(expr);
}
public override AssignmentRhs CloneRHS(AssignmentRhs rhs) {
var r = rhs as ExprRhs;
@@ -799,7 +920,7 @@ namespace Microsoft.Dafny
apply.Args.ForEach(arg => args.Add(CloneExpr(arg)));
var applyClone = new ApplySuffix(Tok(apply.tok), lhsClone, args);
var c = new ExprRhs(applyClone);
- ReportAdditionalInformation(apply.tok, mse.Member.Name);
+ reporter.Info(MessageSource.Cloner, apply.Lhs.tok, mse.Member.Name + suffix);
return c;
}
}
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index 570ac30d..66765b34 100644
--- a/Source/Dafny/Compiler.cs
+++ b/Source/Dafny/Compiler.cs
@@ -14,18 +14,11 @@ using System.Text;
namespace Microsoft.Dafny {
public class Compiler {
- public Compiler(TextWriter wr) {
- Contract.Requires(wr != null);
- this.wr = wr;
+ public Compiler() {
+
}
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(wr!=null);
- }
-
- TextWriter wr;
+ StringBuilder copyInstrWriter = new StringBuilder(); // a buffer that stores copy instructions generated by letExpr that uses out param.
Method enclosingMethod; // non-null when a method body is being translated
FreshIdGenerator idGenerator = new FreshIdGenerator();
@@ -50,7 +43,7 @@ namespace Microsoft.Dafny {
public int ErrorCount;
public TextWriter ErrorWriter = Console.Out;
- void Error(string msg, params object[] args) {
+ void Error(string msg, TextWriter wr, params object[] args) {
Contract.Requires(msg != null);
Contract.Requires(args != null);
@@ -60,7 +53,7 @@ namespace Microsoft.Dafny {
ErrorCount++;
}
- void ReadRuntimeSystem() {
+ void ReadRuntimeSystem(TextWriter wr) {
string codebase = cce.NonNull( System.IO.Path.GetDirectoryName(cce.NonNull(System.Reflection.Assembly.GetExecutingAssembly().Location)));
string path = System.IO.Path.Combine(codebase, "DafnyRuntime.cs");
using (TextReader rd = new StreamReader(new FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read)))
@@ -75,16 +68,16 @@ namespace Microsoft.Dafny {
}
readonly int IndentAmount = 2;
- void Indent(int ind) {
+ void Indent(int ind, TextWriter wr) {
Contract.Requires(0 <= ind);
string spaces = " ";
for (; spaces.Length < ind; ind -= spaces.Length) {
wr.Write(spaces);
}
- wr.Write(spaces.Substring(0, ind));
+ wr.Write(spaces.Substring(0, ind));
}
- public void Compile(Program program) {
+ public void Compile(Program program, TextWriter wr) {
Contract.Requires(program != null);
wr.WriteLine("// Dafny program {0} compiled into C#", program.Name);
wr.WriteLine("// To recompile, use 'csc' with: /r:System.Numerics.dll");
@@ -92,8 +85,8 @@ namespace Microsoft.Dafny {
wr.WriteLine("// You might also want to include compiler switches like:");
wr.WriteLine("// /debug /nowarn:0164 /nowarn:0219");
wr.WriteLine();
- ReadRuntimeSystem();
- CompileBuiltIns(program.BuiltIns);
+ ReadRuntimeSystem(wr);
+ CompileBuiltIns(program.BuiltIns, wr);
foreach (ModuleDefinition m in program.CompileModules) {
if (m.IsAbstract) {
@@ -102,7 +95,11 @@ namespace Microsoft.Dafny {
}
int indent = 0;
if (!m.IsDefaultModule) {
- wr.WriteLine("namespace @{0} {{", m.CompileName);
+ var m_prime = m;
+ while (DafnyOptions.O.IronDafny && m_prime.ClonedFrom != null) {
+ m_prime = m.ClonedFrom;
+ }
+ wr.WriteLine("namespace @{0} {{", m_prime.CompileName);
indent += IndentAmount;
}
foreach (TopLevelDecl d in m.TopLevelDecls) {
@@ -113,21 +110,33 @@ namespace Microsoft.Dafny {
wr.WriteLine();
if (d is OpaqueTypeDecl) {
var at = (OpaqueTypeDecl)d;
- Error("Opaque type ('{0}') cannot be compiled", at.FullName);
+ Error("Opaque type ('{0}') cannot be compiled", wr, at.FullName);
} else if (d is TypeSynonymDecl) {
// do nothing, just bypass type synonyms in the compiler
} else if (d is NewtypeDecl) {
- // do nothing, just bypass newtypes in the compiler
+ var nt = (NewtypeDecl)d;
+ Indent(indent, wr);
+ wr.WriteLine("public class @{0} {{", nt.CompileName);
+ if (nt.NativeType != null) {
+ Indent(indent + IndentAmount, wr);
+ wr.WriteLine("public static System.Collections.Generic.IEnumerable<{0}> IntegerRange(BigInteger lo, BigInteger hi) {{", nt.NativeType.Name);
+ Indent(indent + 2 * IndentAmount, wr);
+ wr.WriteLine("for (var j = lo; j < hi; j++) {{ yield return ({0})j; }}", nt.NativeType.Name);
+ Indent(indent + IndentAmount, wr);
+ wr.WriteLine("}");
+ }
+ Indent(indent, wr);
+ wr.WriteLine("}");
} else if (d is DatatypeDecl) {
var dt = (DatatypeDecl)d;
- Indent(indent);
+ Indent(indent, wr);
wr.Write("public abstract class Base_{0}", dt.CompileName);
if (dt.TypeArgs.Count != 0) {
wr.Write("<{0}>", TypeParameters(dt.TypeArgs));
}
wr.WriteLine(" { }");
- CompileDatatypeConstructors(dt, indent);
- CompileDatatypeStruct(dt, indent);
+ CompileDatatypeConstructors(dt, indent, wr);
+ CompileDatatypeStruct(dt, indent, wr);
} else if (d is IteratorDecl) {
var iter = (IteratorDecl)d;
// An iterator is compiled as follows:
@@ -153,7 +162,7 @@ namespace Microsoft.Dafny {
// }
// }
- Indent(indent);
+ Indent(indent, wr);
wr.Write("public class @{0}", iter.CompileName);
if (iter.TypeArgs.Count != 0) {
wr.Write("<{0}>", TypeParameters(iter.TypeArgs));
@@ -165,58 +174,58 @@ namespace Microsoft.Dafny {
foreach (var member in iter.Members) {
var f = member as Field;
if (f != null && !f.IsGhost) {
- Indent(ind);
- wr.WriteLine("public {0} @{1} = {2};", TypeName(f.Type), f.CompileName, DefaultValue(f.Type));
+ Indent(ind, wr);
+ wr.WriteLine("public {0} @{1} = {2};", TypeName(f.Type, wr), f.CompileName, DefaultValue(f.Type, wr));
} else if (member is Constructor) {
Contract.Assert(ct == null); // we're expecting just one constructor
ct = (Constructor)member;
}
}
Contract.Assert(ct != null); // we do expect a constructor
- Indent(ind); wr.WriteLine("System.Collections.Generic.IEnumerator<object> __iter;");
+ Indent(ind, wr); wr.WriteLine("System.Collections.Generic.IEnumerator<object> __iter;");
// here's the initializer method
- Indent(ind); wr.Write("public void @{0}(", ct.CompileName);
+ Indent(ind, wr); wr.Write("public void @{0}(", ct.CompileName);
string sep = "";
foreach (var p in ct.Ins) {
if (!p.IsGhost) {
// here we rely on the parameters and the corresponding fields having the same names
- wr.Write("{0}{1} @{2}", sep, TypeName(p.Type), p.CompileName);
+ wr.Write("{0}{1} @{2}", sep, TypeName(p.Type, wr), p.CompileName);
sep = ", ";
}
}
wr.WriteLine(") {");
foreach (var p in ct.Ins) {
if (!p.IsGhost) {
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("this.@{0} = @{0};", p.CompileName);
}
}
- Indent(ind + IndentAmount); wr.WriteLine("__iter = TheIterator();");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("__iter = TheIterator();");
+ Indent(ind, wr); wr.WriteLine("}");
// here are the enumerator methods
- Indent(ind); wr.WriteLine("public void MoveNext(out bool more) { more = __iter.MoveNext(); }");
- Indent(ind); wr.WriteLine("private System.Collections.Generic.IEnumerator<object> TheIterator() {");
+ Indent(ind, wr); wr.WriteLine("public void MoveNext(out bool more) { more = __iter.MoveNext(); }");
+ Indent(ind, wr); wr.WriteLine("private System.Collections.Generic.IEnumerator<object> TheIterator() {");
if (iter.Body == null) {
- Error("Iterator {0} has no body", iter.FullName);
+ Error("Iterator {0} has no body", wr, iter.FullName);
} else {
- TrStmt(iter.Body, ind + IndentAmount);
+ wr.Write(TrStmt(iter.Body, ind + IndentAmount).ToString());
}
- Indent(ind + IndentAmount); wr.WriteLine("yield break;");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("yield break;");
+ Indent(ind, wr); wr.WriteLine("}");
// end of the class
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("}");
}
else if (d is TraitDecl)
{
//writing the trait
var trait = (TraitDecl)d;
- Indent(indent);
+ Indent(indent, wr);
wr.Write("public interface @{0}", trait.CompileName);
wr.WriteLine(" {");
- CompileClassMembers(trait, false, indent + IndentAmount);
- Indent(indent); wr.WriteLine("}");
+ CompileClassMembers(trait, false, indent + IndentAmount, wr);
+ Indent(indent, wr); wr.WriteLine("}");
//writing the _Companion class
List<MemberDecl> members = new List<MemberDecl>();
@@ -236,27 +245,27 @@ namespace Microsoft.Dafny {
}
}
}
- Indent(indent);
+ Indent(indent, wr);
wr.Write("public class @_Companion_{0}", trait.CompileName);
wr.WriteLine(" {");
- CompileClassMembers(trait, true, indent + IndentAmount);
- Indent(indent); wr.WriteLine("}");
+ CompileClassMembers(trait, true, indent + IndentAmount, wr);
+ Indent(indent, wr); wr.WriteLine("}");
}
else if (d is ClassDecl) {
var cl = (ClassDecl)d;
- Indent(indent);
- wr.Write("public class @{0}", cl.CompileName);
+ Indent(indent, wr);
+ wr.Write("public partial class @{0}", cl.CompileName);
if (cl.TypeArgs.Count != 0) {
wr.Write("<{0}>", TypeParameters(cl.TypeArgs));
}
string sep = " : ";
foreach (var trait in cl.TraitsTyp) {
- wr.Write("{0}{1}", sep, TypeName(trait));
+ wr.Write("{0}{1}", sep, TypeName(trait, wr));
sep = ", ";
}
wr.WriteLine(" {");
- CompileClassMembers(cl, false, indent+IndentAmount);
- Indent(indent); wr.WriteLine("}");
+ CompileClassMembers(cl, false, indent+IndentAmount, wr);
+ Indent(indent, wr); wr.WriteLine("}");
} else if (d is ModuleDecl) {
// nop
} else { Contract.Assert(false); }
@@ -267,15 +276,15 @@ namespace Microsoft.Dafny {
}
}
- void CompileBuiltIns(BuiltIns builtIns) {
+ void CompileBuiltIns(BuiltIns builtIns, TextWriter wr) {
wr.WriteLine("namespace Dafny {");
- Indent(IndentAmount);
+ Indent(IndentAmount, wr);
wr.WriteLine("public partial class Helpers {");
foreach (var decl in builtIns.SystemModule.TopLevelDecls) {
if (decl is ArrayClassDecl) {
int dims = ((ArrayClassDecl)decl).Dims;
// public static T[,] InitNewArray2<T>(BigInteger size0, BigInteger size1) {
- Indent(3 * IndentAmount);
+ Indent(3 * IndentAmount, wr);
wr.Write("public static T[");
RepeatWrite(wr, dims, "", ",");
wr.Write("] InitNewArray{0}<T>(", dims);
@@ -283,52 +292,52 @@ namespace Microsoft.Dafny {
wr.WriteLine(") {");
// int s0 = (int)size0;
for (int i = 0; i < dims; i++) {
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.WriteLine("int s{0} = (int)size{0};", i);
}
// T[,] a = new T[s0, s1];
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.Write("T[");
RepeatWrite(wr, dims, "", ",");
wr.Write("] a = new T[");
RepeatWrite(wr, dims, "s{0}", ",");
wr.WriteLine("];");
// BigInteger[,] b = a as BigInteger[,];
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.Write("BigInteger[");
RepeatWrite(wr, dims, "", ",");
wr.Write("] b = a as BigInteger[");
RepeatWrite(wr, dims, "", ",");
wr.WriteLine("];");
// if (b != null) {
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.WriteLine("if (b != null) {");
// BigInteger z = new BigInteger(0);
- Indent(5 * IndentAmount);
+ Indent(5 * IndentAmount, wr);
wr.WriteLine("BigInteger z = new BigInteger(0);");
// for (int i0 = 0; i0 < s0; i0++)
// for (int i1 = 0; i1 < s1; i1++)
for (int i = 0; i < dims; i++) {
- Indent((5+i) * IndentAmount);
+ Indent((5+i) * IndentAmount, wr);
wr.WriteLine("for (int i{0} = 0; i{0} < s{0}; i{0}++)", i);
}
// b[i0,i1] = z;
- Indent((5+dims) * IndentAmount);
+ Indent((5+dims) * IndentAmount, wr);
wr.Write("b[");
RepeatWrite(wr, dims, "i{0}", ",");
wr.WriteLine("] = z;");
// }
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.WriteLine("}");
// return a;
- Indent(4 * IndentAmount);
+ Indent(4 * IndentAmount, wr);
wr.WriteLine("return a;");
// }
- Indent(3 * IndentAmount);
+ Indent(3 * IndentAmount, wr);
wr.WriteLine("}"); // end of method
}
}
- Indent(IndentAmount);
+ Indent(IndentAmount, wr);
wr.WriteLine("}"); // end of class Helpers
wr.WriteLine("}"); // end of namespace
}
@@ -343,7 +352,7 @@ namespace Microsoft.Dafny {
}
}
- void CompileDatatypeConstructors(DatatypeDecl dt, int indent)
+ void CompileDatatypeConstructors(DatatypeDecl dt, int indent, TextWriter wr)
{
Contract.Requires(dt != null);
@@ -356,20 +365,20 @@ namespace Microsoft.Dafny {
// public Dt__Lazy(Computer c) { this.c = c; }
// public Base_Dt<T> Get() { return c(); }
// }
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("public class {0}__Lazy{1} : Base_{0}{1} {{", dt.CompileName, typeParams);
int ind = indent + IndentAmount;
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public delegate Base_{0}{1} Computer();", dt.CompileName, typeParams);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public delegate Computer ComputerComputer();");
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("Computer c;");
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public {0}__Lazy(Computer c) {{ this.c = c; }}", dt.CompileName);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public Base_{0}{1} Get() {{ return c(); }}", dt.CompileName, typeParams);
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("}");
}
@@ -391,7 +400,7 @@ namespace Microsoft.Dafny {
// // ...
// }
// }
- Indent(indent);
+ Indent(indent, wr);
wr.Write("public class {0}", DtCtorDeclarationName(ctor, dt.TypeArgs));
wr.WriteLine(" : Base_{0}{1} {{", dt.CompileName, typeParams);
int ind = indent + IndentAmount;
@@ -399,32 +408,32 @@ namespace Microsoft.Dafny {
int i = 0;
foreach (Formal arg in ctor.Formals) {
if (!arg.IsGhost) {
- Indent(ind);
- wr.WriteLine("public readonly {0} @{1};", TypeName(arg.Type), FormalName(arg, i));
+ Indent(ind, wr);
+ wr.WriteLine("public readonly {0} @{1};", TypeName(arg.Type, wr), FormalName(arg, i));
i++;
}
}
- Indent(ind);
+ Indent(ind, wr);
wr.Write("public {0}(", DtCtorDeclartionName(ctor));
- WriteFormals("", ctor.Formals);
+ WriteFormals("", ctor.Formals, wr);
wr.WriteLine(") {");
i = 0;
foreach (Formal arg in ctor.Formals) {
if (!arg.IsGhost) {
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("this.@{0} = @{0};", FormalName(arg, i));
i++;
}
}
- Indent(ind); wr.WriteLine("}");
+ Indent(ind, wr); wr.WriteLine("}");
// Equals method
- Indent(ind); wr.WriteLine("public override bool Equals(object other) {");
- Indent(ind + IndentAmount);
+ Indent(ind, wr); wr.WriteLine("public override bool Equals(object other) {");
+ Indent(ind + IndentAmount, wr);
wr.Write("var oth = other as {0}", DtCtorName(ctor, dt.TypeArgs));
wr.WriteLine(";");
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.Write("return oth != null");
i = 0;
foreach (Formal arg in ctor.Formals) {
@@ -439,56 +448,76 @@ namespace Microsoft.Dafny {
}
}
wr.WriteLine(";");
- Indent(ind); wr.WriteLine("}");
-
- // GetHashCode method
- Indent(ind); wr.WriteLine("public override int GetHashCode() {");
- Indent(ind + IndentAmount); wr.Write("return " + constructorIndex);
+ Indent(ind, wr); wr.WriteLine("}");
+ // GetHashCode method (Uses the djb2 algorithm)
+ Indent(ind, wr); wr.WriteLine("public override int GetHashCode() {");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("ulong hash = 5381;");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("hash = ((hash << 5) + hash) + {0};", constructorIndex);
i = 0;
foreach (Formal arg in ctor.Formals) {
if (!arg.IsGhost) {
string nm = FormalName(arg, i);
- wr.Write(" ^ this.@{0}.GetHashCode()", nm);
+ Indent(ind + IndentAmount, wr); wr.WriteLine("hash = ((hash << 5) + hash) + ((ulong)this.@{0}.GetHashCode());", nm);
i++;
}
}
- wr.WriteLine(";");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("return (int) hash;");
+ Indent(ind, wr); wr.WriteLine("}");
if (dt is IndDatatypeDecl) {
- Indent(ind); wr.WriteLine("public override string ToString() {");
+ Indent(ind, wr); wr.WriteLine("public override string ToString() {");
string nm;
if (dt is TupleTypeDecl) {
nm = "";
} else {
nm = (dt.Module.IsDefaultModule ? "" : dt.Module.CompileName + ".") + dt.CompileName + "." + ctor.CompileName;
}
- Indent(ind + IndentAmount); wr.WriteLine("string s = \"{0}\";", nm);
+ var tempVar = GenVarName("s", ctor.Formals);
+ Indent(ind + IndentAmount, wr); wr.WriteLine("string {0} = \"{1}\";", tempVar, nm);
if (ctor.Formals.Count != 0) {
- Indent(ind + IndentAmount); wr.WriteLine("s += \"(\";");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("{0} += \"(\";", tempVar);
i = 0;
foreach (var arg in ctor.Formals) {
if (!arg.IsGhost) {
if (i != 0) {
- Indent(ind + IndentAmount); wr.WriteLine("s += \", \";");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("{0} += \", \";", tempVar);
}
- Indent(ind + IndentAmount); wr.WriteLine("s += @{0}.ToString();", FormalName(arg, i));
+ Indent(ind + IndentAmount, wr); wr.WriteLine("{0} += @{1}.ToString();", tempVar,FormalName(arg, i));
i++;
}
}
- Indent(ind + IndentAmount); wr.WriteLine("s += \")\";");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("{0} += \")\";", tempVar);
}
- Indent(ind + IndentAmount); wr.WriteLine("return s;");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("return {0};", tempVar);
+ Indent(ind, wr); wr.WriteLine("}");
}
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("}");
}
constructorIndex++;
}
- void CompileDatatypeStruct(DatatypeDecl dt, int indent) {
+ // create a varName that is not a duplicate of formals' name
+ string GenVarName(string root, List<Formal> formals) {
+ bool finished = false;
+ while (!finished) {
+ finished = true;
+ int i = 0;
+ foreach (var arg in formals) {
+ if (!arg.IsGhost) {
+ if (root.Equals(FormalName(arg, i))) {
+ root += root;
+ finished = false;
+ }
+ i++;
+ }
+ }
+ }
+ return root;
+ }
+
+ void CompileDatatypeStruct(DatatypeDecl dt, int indent, TextWriter wr) {
Contract.Requires(dt != null);
// public struct Dt<T> : IDatatype{
@@ -532,46 +561,46 @@ namespace Microsoft.Dafny {
DtT += DtT_TypeArgs;
}
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("public struct @{0} {{", DtT);
int ind = indent + IndentAmount;
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("Base_{0} _d;", DtT);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public Base_{0} _D {{", DtT);
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("get {");
- Indent(ind + 2 * IndentAmount);
+ Indent(ind + 2 * IndentAmount, wr);
wr.WriteLine("if (_d == null) {");
- Indent(ind + 3 * IndentAmount);
+ Indent(ind + 3 * IndentAmount, wr);
wr.WriteLine("_d = Default;");
if (dt is CoDatatypeDecl) {
string typeParams = dt.TypeArgs.Count == 0 ? "" : string.Format("<{0}>", TypeParameters(dt.TypeArgs));
- Indent(ind + 2 * IndentAmount);
+ Indent(ind + 2 * IndentAmount, wr);
wr.WriteLine("}} else if (_d is {0}__Lazy{1}) {{", dt.CompileName, typeParams);
- Indent(ind + 3 * IndentAmount);
+ Indent(ind + 3 * IndentAmount, wr);
wr.WriteLine("_d = (({0}__Lazy{1})_d).Get();", dt.CompileName, typeParams);
}
- Indent(ind + 2 * IndentAmount); wr.WriteLine("}");
- Indent(ind + 2 * IndentAmount); wr.WriteLine("return _d;");
- Indent(ind + IndentAmount); wr.WriteLine("}");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind + 2 * IndentAmount, wr); wr.WriteLine("}");
+ Indent(ind + 2 * IndentAmount, wr); wr.WriteLine("return _d;");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("}");
+ Indent(ind, wr); wr.WriteLine("}");
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public @{0}(Base_{1} d) {{ this._d = d; }}", dt.CompileName, DtT);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("static Base_{0} theDefault;", DtT);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public static Base_{0} Default {{", DtT);
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("get {");
- Indent(ind + 2 * IndentAmount);
+ Indent(ind + 2 * IndentAmount, wr);
wr.WriteLine("if (theDefault == null) {");
- Indent(ind + 3 * IndentAmount);
+ Indent(ind + 3 * IndentAmount, wr);
wr.Write("theDefault = ");
DatatypeCtor defaultCtor;
@@ -585,55 +614,55 @@ namespace Microsoft.Dafny {
string sep = "";
foreach (Formal f in defaultCtor.Formals) {
if (!f.IsGhost) {
- wr.Write("{0}{1}", sep, DefaultValue(f.Type));
+ wr.Write("{0}{1}", sep, DefaultValue(f.Type, wr));
sep = ", ";
}
}
wr.Write(")");
wr.WriteLine(";");
- Indent(ind + 2 * IndentAmount);
+ Indent(ind + 2 * IndentAmount, wr);
wr.WriteLine("}");
- Indent(ind + 2 * IndentAmount);
+ Indent(ind + 2 * IndentAmount, wr);
wr.WriteLine("return theDefault;");
- Indent(ind + IndentAmount); wr.WriteLine("}");
+ Indent(ind + IndentAmount, wr); wr.WriteLine("}");
- Indent(ind); wr.WriteLine("}");
+ Indent(ind, wr); wr.WriteLine("}");
- Indent(ind); wr.WriteLine("public override bool Equals(object other) {");
- Indent(ind + IndentAmount);
+ Indent(ind, wr); wr.WriteLine("public override bool Equals(object other) {");
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("return other is @{0} && _D.Equals(((@{0})other)._D);", DtT);
- Indent(ind); wr.WriteLine("}");
+ Indent(ind, wr); wr.WriteLine("}");
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public override int GetHashCode() { return _D.GetHashCode(); }");
if (dt is IndDatatypeDecl) {
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public override string ToString() { return _D.ToString(); }");
}
// query properties
foreach (var ctor in dt.Ctors) {
// public bool is_Ctor0 { get { return _D is Dt_Ctor0; } }
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public bool is_{0} {{ get {{ return _D is {1}_{0}{2}; }} }}", ctor.CompileName, dt.CompileName, DtT_TypeArgs);
}
if (dt.HasFinitePossibleValues) {
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("public static System.Collections.Generic.IEnumerable<@{0}> AllSingletonConstructors {{", DtT);
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("get {");
foreach (var ctr in dt.Ctors) {
if (ctr.Formals.Count == 0) {
- Indent(ind + IndentAmount + IndentAmount);
+ Indent(ind + IndentAmount + IndentAmount, wr);
wr.WriteLine("yield return new @{0}(new {2}_{1}());", DtT, ctr.CompileName, dt.CompileName);
}
}
- Indent(ind + IndentAmount + IndentAmount);
+ Indent(ind + IndentAmount + IndentAmount, wr);
wr.WriteLine("yield break;");
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("}");
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("}");
}
@@ -642,17 +671,17 @@ namespace Microsoft.Dafny {
foreach (var arg in ctor.Formals) {
if (!arg.IsGhost && arg.HasName) {
// public T0 @Dtor0 { get { return ((DT_Ctor)_D).@Dtor0; } }
- Indent(ind);
- wr.WriteLine("public {0} dtor_{1} {{ get {{ return (({2}_{3}{4})_D).@{1}; }} }}", TypeName(arg.Type), arg.CompileName, dt.CompileName, ctor.CompileName, DtT_TypeArgs);
+ Indent(ind, wr);
+ wr.WriteLine("public {0} dtor_{1} {{ get {{ return (({2}_{3}{4})_D).@{1}; }} }}", TypeName(arg.Type, wr), arg.CompileName, dt.CompileName, ctor.CompileName, DtT_TypeArgs);
}
}
}
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("}");
}
- int WriteFormals(string sep, List<Formal/*!*/>/*!*/ formals)
+ int WriteFormals(string sep, List<Formal/*!*/>/*!*/ formals, TextWriter wr)
{
Contract.Requires(sep != null);
Contract.Requires(cce.NonNullElements(formals));
@@ -660,7 +689,7 @@ namespace Microsoft.Dafny {
foreach (Formal arg in formals) {
if (!arg.IsGhost) {
string name = FormalName(arg, i);
- wr.Write("{0}{1}{2} @{3}", sep, arg.InParam ? "" : "out ", TypeName(arg.Type), name);
+ wr.Write("{0}{1}{2} @{3}", sep, arg.InParam ? "" : "out ", TypeName(arg.Type, wr), name);
sep = ", ";
i++;
}
@@ -676,7 +705,11 @@ namespace Microsoft.Dafny {
}
string DtName(DatatypeDecl decl) {
- return decl.Module.IsDefaultModule ? decl.CompileName : decl.FullCompileName;
+ var d = (TopLevelDecl)decl;
+ while (DafnyOptions.O.IronDafny && d.ClonedFrom != null) {
+ d = (TopLevelDecl)d.ClonedFrom;
+ }
+ return d.Module.IsDefaultModule ? d.CompileName : d.FullCompileName;
}
string DtCtorName(DatatypeCtor ctor) {
Contract.Requires(ctor != null);
@@ -712,51 +745,80 @@ namespace Microsoft.Dafny {
return s;
}
- string DtCtorName(DatatypeCtor ctor, List<Type> typeArgs) {
+ string DtCtorName(DatatypeCtor ctor, List<Type> typeArgs, TextWriter wr) {
Contract.Requires(ctor != null);
Contract.Ensures(Contract.Result<string>() != null);
var s = DtCtorName(ctor);
if (typeArgs != null && typeArgs.Count != 0) {
- s += "<" + TypeNames(typeArgs) + ">";
+ s += "<" + TypeNames(typeArgs, wr) + ">";
}
return s;
}
public bool HasMain(Program program) {
+ Method mainMethod = null;
+ bool hasMain = false;
foreach (var module in program.Modules) {
+ if (module.IsAbstract) {
+ // the purpose of an abstract module is to skip compilation
+ continue;
+ }
foreach (var decl in module.TopLevelDecls) {
var c = decl as ClassDecl;
if (c != null) {
foreach (var member in c.Members) {
var m = member as Method;
if (m != null && IsMain(m)) {
- return true;
+ if (mainMethod == null) {
+ mainMethod = m;
+ hasMain = true;
+ } else {
+ // more than one main in the program
+ ErrorWriter.WriteLine("More than one method is declared as \"main\"");
+ ErrorCount++;
+ hasMain = false;
+ }
}
}
}
}
}
- return false;
+ return hasMain;
}
public static bool IsMain(Method m) {
// In order to be a legal Main() method, the following must be true:
- // The method takes no parameters
+ // The method takes no parameters
// The method is not a ghost method
// The method has no requires clause
// The method has no modifies clause
// If the method is an instance (that is, non-static) method in a class, then the enclosing class must not declare any constructor
- if (!m.IsGhost && m.Name == "Main" && m.TypeArgs.Count == 0 && m.Ins.Count == 0 && m.Outs.Count == 0 && m.Req.Count == 0
+ // Or if a method is annotated with {:main} and the above restrictions apply, except it is allowed to take ghost arguments,
+ // and it is allowed to have preconditions and modifies. This lets the programmer add some explicit assumptions about the outside world,
+ // modeled, for example, via ghost parameters.
+ if (!m.IsGhost && m.Name == "Main" && m.TypeArgs.Count == 0 && m.Ins.Count == 0 && m.Outs.Count == 0 && m.Req.Count == 0
&& m.Mod.Expressions.Count == 0 && (m.IsStatic || (((ClassDecl)m.EnclosingClass) == null) || !((ClassDecl)m.EnclosingClass).HasConstructor)) {
return true;
- }
- else {
+ } else if (Attributes.Contains(m.Attributes, "main") && !m.IsGhost && m.TypeArgs.Count == 0 && m.Outs.Count == 0
+ && (m.IsStatic || (((ClassDecl)m.EnclosingClass) == null) || !((ClassDecl)m.EnclosingClass).HasConstructor)) {
+ if (m.Ins.Count == 0) {
+ return true;
+ } else {
+ bool isGhost = true;
+ foreach (var arg in m.Ins) {
+ if (!arg.IsGhost) {
+ isGhost = false;
+ }
+ }
+ return isGhost;
+ }
+ } else {
return false;
}
}
- void CompileClassMembers(ClassDecl c, bool forCompanionClass, int indent) {
+ void CompileClassMembers(ClassDecl c, bool forCompanionClass, int indent, TextWriter wr) {
Contract.Requires(c != null);
Contract.Requires(!forCompanionClass || c is TraitDecl);
Contract.Requires(0 <= indent);
@@ -765,9 +827,9 @@ namespace Microsoft.Dafny {
if (member is Field) {
var f = (Field)member;
// every field is inherited
- Indent(indent);
- wr.WriteLine("public {0} @_{1};", TypeName(f.Type), f.CompileName);
- wr.Write("public {0} @{1}", TypeName(f.Type), f.CompileName);
+ Indent(indent, wr);
+ wr.WriteLine("public {0} @_{1};", TypeName(f.Type, wr), f.CompileName);
+ wr.Write("public {0} @{1}", TypeName(f.Type, wr), f.CompileName);
wr.WriteLine(" {");
wr.WriteLine(" get { ");
wr.Write("return this.@_{0};", f.CompileName);
@@ -779,11 +841,11 @@ namespace Microsoft.Dafny {
} else if (member is Function) {
var f = (Function)member;
Contract.Assert(f.Body != null);
- CompileFunction(indent, f);
+ CompileFunction(indent, f, wr);
} else if (member is Method) {
var method = (Method)member;
Contract.Assert(method.Body != null);
- CompileMethod(c, indent, method);
+ CompileMethod(c, indent, method, wr);
} else {
Contract.Assert(false); // unexpected member
}
@@ -794,12 +856,12 @@ namespace Microsoft.Dafny {
if (f.IsGhost || forCompanionClass) {
// emit nothing
} else if (c is TraitDecl) {
- Indent(indent);
- wr.Write("{0} @{1}", TypeName(f.Type), f.CompileName);
+ Indent(indent, wr);
+ wr.Write("{0} @{1}", TypeName(f.Type, wr), f.CompileName);
wr.WriteLine(" { get; set; }");
} else {
- Indent(indent);
- wr.WriteLine("public {0} @{1} = {2};", TypeName(f.Type), f.CompileName, DefaultValue(f.Type));
+ Indent(indent, wr);
+ wr.WriteLine("public {0} @{1} = {2};", TypeName(f.Type, wr), f.CompileName, DefaultValue(f.Type, wr));
}
} else if (member is Function) {
var f = (Function)member;
@@ -808,29 +870,29 @@ namespace Microsoft.Dafny {
if (forCompanionClass || Attributes.Contains(f.Attributes, "axiom")) {
// suppress error message (in the case of "forCompanionClass", the non-forCompanionClass call will produce the error message)
} else {
- Error("Function {0} has no body", f.FullName);
+ Error("Function {0} has no body", wr, f.FullName);
}
} else if (f.IsGhost) {
// nothing to compile, but we do check for assumes
if (f.Body == null) {
Contract.Assert(c is TraitDecl && !f.IsStatic);
} else {
- var v = new CheckHasNoAssumes_Visitor(this);
+ var v = new CheckHasNoAssumes_Visitor(this, wr);
v.Visit(f.Body);
}
} else if (c is TraitDecl && !forCompanionClass) {
// include it, unless it's static
if (!f.IsStatic) {
- Indent(indent);
- wr.Write("{0} @{1}", TypeName(f.ResultType), f.CompileName);
+ Indent(indent, wr);
+ wr.Write("{0} @{1}", TypeName(f.ResultType, wr), f.CompileName);
wr.Write("(");
- WriteFormals("", f.Formals);
+ WriteFormals("", f.Formals, wr);
wr.WriteLine(");");
}
} else if (forCompanionClass && !f.IsStatic) {
// companion classes only has static members
} else {
- CompileFunction(indent, f);
+ CompileFunction(indent, f, wr);
}
} else if (member is Method) {
var m = (Method)member;
@@ -839,30 +901,30 @@ namespace Microsoft.Dafny {
if (forCompanionClass || Attributes.Contains(m.Attributes, "axiom")) {
// suppress error message (in the case of "forCompanionClass", the non-forCompanionClass call will produce the error message)
} else {
- Error("Method {0} has no body", m.FullName);
+ Error("Method {0} has no body", wr, m.FullName);
}
} else if (m.IsGhost) {
// nothing to compile, but we do check for assumes
if (m.Body == null) {
Contract.Assert(c is TraitDecl && !m.IsStatic);
} else {
- var v = new CheckHasNoAssumes_Visitor(this);
+ var v = new CheckHasNoAssumes_Visitor(this, wr);
v.Visit(m.Body);
}
} else if (c is TraitDecl && !forCompanionClass) {
// include it, unless it's static
if (!m.IsStatic) {
- Indent(indent);
+ Indent(indent, wr);
wr.Write("void @{0}", m.CompileName);
wr.Write("(");
- int nIns = WriteFormals("", m.Ins);
- WriteFormals(nIns == 0 ? "" : ", ", m.Outs);
+ int nIns = WriteFormals("", m.Ins, wr);
+ WriteFormals(nIns == 0 ? "" : ", ", m.Outs, wr);
wr.WriteLine(");");
}
} else if (forCompanionClass && !m.IsStatic) {
// companion classes only has static members
} else {
- CompileMethod(c, indent, m);
+ CompileMethod(c, indent, m, wr);
}
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member
@@ -870,85 +932,218 @@ namespace Microsoft.Dafny {
}
}
- private void CompileFunction(int indent, Function f) {
- Indent(indent);
- wr.Write("public {0}{1} @{2}", f.IsStatic ? "static " : "", TypeName(f.ResultType), f.CompileName);
+ private void CompileFunction(int indent, Function f, TextWriter wr) {
+ Indent(indent, wr);
+ wr.Write("public {0}{1} @{2}", f.IsStatic ? "static " : "", TypeName(f.ResultType, wr), f.CompileName);
if (f.TypeArgs.Count != 0) {
wr.Write("<{0}>", TypeParameters(f.TypeArgs));
}
wr.Write("(");
- WriteFormals("", f.Formals);
+ WriteFormals("", f.Formals, wr);
wr.WriteLine(") {");
- CompileReturnBody(f.Body, indent + IndentAmount);
- Indent(indent); wr.WriteLine("}");
+ CompileReturnBody(f.Body, indent + IndentAmount, wr);
+ Indent(indent, wr); wr.WriteLine("}");
}
- private void CompileMethod(ClassDecl c, int indent, Method m) {
- Indent(indent);
+ private void CompileMethod(ClassDecl c, int indent, Method m, TextWriter wr) {
+ Indent(indent, wr);
wr.Write("public {0}void @{1}", m.IsStatic ? "static " : "", m.CompileName);
if (m.TypeArgs.Count != 0) {
wr.Write("<{0}>", TypeParameters(m.TypeArgs));
}
wr.Write("(");
- int nIns = WriteFormals("", m.Ins);
- WriteFormals(nIns == 0 ? "" : ", ", m.Outs);
+ int nIns = WriteFormals("", m.Ins, wr);
+ WriteFormals(nIns == 0 ? "" : ", ", m.Outs, wr);
wr.WriteLine(")");
- Indent(indent); wr.WriteLine("{");
+ Indent(indent, wr); wr.WriteLine("{");
foreach (Formal p in m.Outs) {
if (!p.IsGhost) {
- Indent(indent + IndentAmount);
- wr.WriteLine("@{0} = {1};", p.CompileName, DefaultValue(p.Type));
+ Indent(indent + IndentAmount, wr);
+ wr.WriteLine("@{0} = {1};", p.CompileName, DefaultValue(p.Type, wr));
}
}
if (m.Body == null) {
- Error("Method {0} has no body", m.FullName);
+ Error("Method {0} has no body", wr, m.FullName);
} else {
if (m.IsTailRecursive) {
- Indent(indent); wr.WriteLine("TAIL_CALL_START: ;");
if (!m.IsStatic) {
- Indent(indent + IndentAmount); wr.WriteLine("var _this = this;");
+ Indent(indent + IndentAmount, wr); wr.WriteLine("var _this = this;");
}
+ Indent(indent, wr); wr.WriteLine("TAIL_CALL_START: ;");
}
Contract.Assert(enclosingMethod == null);
enclosingMethod = m;
- TrStmtList(m.Body.Body, indent);
+ TrStmtList(m.Body.Body, indent, wr);
Contract.Assert(enclosingMethod == m);
enclosingMethod = null;
}
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("}");
// allow the Main method to be an instance method
- if (!m.IsStatic && IsMain(m)) {
- Indent(indent);
+ if (IsMain(m) && (!m.IsStatic || m.CompileName != "Main")) {
+ Indent(indent, wr);
wr.WriteLine("public static void Main(string[] args) {");
- Contract.Assert(m.EnclosingClass == c);
- Indent(indent + IndentAmount);
- wr.Write("@{0} b = new @{0}", c.CompileName);
- if (c.TypeArgs.Count != 0) {
- // instantiate every parameter, it doesn't particularly matter how
- wr.Write("<");
- string sep = "";
- for (int i = 0; i < c.TypeArgs.Count; i++) {
- wr.Write("{0}int", sep);
- sep = ", ";
+ if (!m.IsStatic) {
+ Contract.Assert(m.EnclosingClass == c);
+ Indent(indent + IndentAmount, wr);
+ wr.Write("@{0} b = new @{0}", c.CompileName);
+ if (c.TypeArgs.Count != 0) {
+ // instantiate every parameter, it doesn't particularly matter how
+ wr.Write("<");
+ string sep = "";
+ for (int i = 0; i < c.TypeArgs.Count; i++) {
+ wr.Write("{0}int", sep);
+ sep = ", ";
+ }
+ wr.Write(">");
}
- wr.Write(">");
+ wr.WriteLine("();");
+ Indent(indent + IndentAmount, wr); wr.WriteLine("b.@{0}();", m.CompileName);
+ } else {
+ Indent(indent + IndentAmount, wr); wr.WriteLine("@{0}();", m.CompileName);
}
- wr.WriteLine("();");
- Indent(indent + IndentAmount); wr.WriteLine("b.@Main();");
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("}");
}
}
- void CompileReturnBody(Expression body, int indent) {
- Contract.Requires(0 <= indent);
- body = body.Resolved;
- Indent(indent);
+ void TrCasePatternOpt(CasePattern pat, Expression rhs, string rhs_string, int indent, TextWriter wr, bool inLetExprBody) {
+ Contract.Requires(pat != null);
+ Contract.Requires(pat.Var != null || rhs != null);
+ if (pat.Var != null) {
+ // The trivial Dafny "pattern" expression
+ // var x := G
+ // is translated into C# as:
+ // var x := G;
+ var bv = pat.Var;
+ if (!bv.IsGhost) {
+ Indent(indent, wr);
+ wr.Write("{0} {1} = ", TypeName(bv.Type, wr), "@" + bv.CompileName);
+ if (rhs != null) {
+ TrExpr(rhs, wr, inLetExprBody);
+ } else {
+ wr.Write(rhs_string);
+ }
+ wr.Write(";\n");
+ }
+ } else if (pat.Arguments != null) {
+ // The Dafny "pattern" expression
+ // var Pattern(x,y) := G
+ // is translated into C# as:
+ // var tmp := G;
+ // var x := dtorX(tmp);
+ // var y := dtorY(tmp);
+ var ctor = pat.Ctor;
+ Contract.Assert(ctor != null); // follows from successful resolution
+ Contract.Assert(pat.Arguments.Count == ctor.Formals.Count); // follows from successful resolution
+
+ // Create the temporary variable to hold G
+ var tmp_name = idGenerator.FreshId("_let_tmp_rhs");
+ Indent(indent, wr);
+ wr.Write("{0} {1} = ", TypeName(rhs.Type, wr), tmp_name);
+ TrExpr(rhs, wr, inLetExprBody);
+ wr.WriteLine(";");
+
+ var k = 0; // number of non-ghost formals processed
+ for (int i = 0; i < pat.Arguments.Count; i++) {
+ var arg = pat.Arguments[i];
+ var formal = ctor.Formals[i];
+ if (formal.IsGhost) {
+ // nothing to compile, but do a sanity check
+ Contract.Assert(!Contract.Exists(arg.Vars, bv => !bv.IsGhost));
+ } else {
+ TrCasePatternOpt(arg, null, string.Format("(({0})({1})._D).@{2}", DtCtorName(ctor, ((DatatypeValue)pat.Expr).InferredTypeArgs, wr), tmp_name, FormalName(formal, k)), indent, wr, inLetExprBody);
+ k++;
+ }
+ }
+ }
+ }
+
+ void ReturnExpr(Expression expr, int indent, TextWriter wr, bool inLetExprBody) {
+ Indent(indent, wr);
wr.Write("return ");
- TrExpr(body);
+ TrExpr(expr, wr, inLetExprBody);
wr.WriteLine(";");
}
+ void TrExprOpt(Expression expr, int indent, TextWriter wr, bool inLetExprBody) {
+ Contract.Requires(expr != null);
+ if (expr is LetExpr) {
+ var e = (LetExpr)expr;
+ if (e.Exact) {
+ for (int i = 0; i < e.LHSs.Count; i++) {
+ var lhs = e.LHSs[i];
+ if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) {
+ TrCasePatternOpt(lhs, e.RHSs[i], null, indent, wr, inLetExprBody);
+ }
+ }
+ TrExprOpt(e.Body, indent, wr, inLetExprBody);
+ } else {
+ // We haven't optimized the other cases, so fallback to normal compilation
+ ReturnExpr(e, indent, wr, inLetExprBody);
+ }
+ } else if (expr is ITEExpr) {
+ ITEExpr e = (ITEExpr)expr;
+ Indent(indent, wr);
+ wr.Write("if (");
+ TrExpr(e.Test, wr, inLetExprBody);
+ wr.Write(") {\n");
+ TrExprOpt(e.Thn, indent + IndentAmount, wr, inLetExprBody);
+ Indent(indent, wr);
+ wr.WriteLine("} else {");
+ TrExprOpt(e.Els, indent + IndentAmount, wr, inLetExprBody);
+ Indent(indent, wr);
+ wr.WriteLine("}");
+ } else if (expr is MatchExpr) {
+ var e = (MatchExpr)expr;
+ // var _source = E;
+ // if (source.is_Ctor0) {
+ // FormalType f0 = ((Dt_Ctor0)source._D).a0;
+ // ...
+ // return Body0;
+ // } else if (...) {
+ // ...
+ // } else if (true) {
+ // ...
+ // }
+ string source = idGenerator.FreshId("_source");
+ Indent(indent, wr);
+ wr.Write("{0} {1} = ", TypeName(e.Source.Type, wr), source);
+ TrExpr(e.Source, wr, inLetExprBody);
+ wr.WriteLine(";");
+
+ if (e.Cases.Count == 0) {
+ // the verifier would have proved we never get here; still, we need some code that will compile
+ wr.Write("throw new System.Exception();");
+ } else {
+ int i = 0;
+ var sourceType = (UserDefinedType)e.Source.Type.NormalizeExpand();
+ foreach (MatchCaseExpr mc in e.Cases) {
+ //Indent(indent);
+ MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, e.Cases.Count, indent, wr);
+ TrExprOpt(mc.Body, indent + IndentAmount, wr, inLetExprBody);
+ i++;
+ }
+ Indent(indent, wr);
+ wr.WriteLine("}");
+ }
+ } else if (expr is StmtExpr) {
+ var e = (StmtExpr)expr;
+ TrExprOpt(e.E, indent, wr, inLetExprBody);
+ } else {
+ // We haven't optimized any other cases, so fallback to normal compilation
+ ReturnExpr(expr, indent, wr, inLetExprBody);
+ }
+ }
+
+ void CompileReturnBody(Expression body, int indent, TextWriter wr) {
+ Contract.Requires(0 <= indent);
+ body = body.Resolved;
+ //Indent(indent);
+ //wr.Write("return ");
+ TrExprOpt(body, indent, wr, false);
+ //wr.WriteLine(";");
+ }
+
// ----- Type ---------------------------------------------------------------------------------
readonly string DafnySetClass = "Dafny.Set";
@@ -964,168 +1159,207 @@ namespace Microsoft.Dafny {
return null;
}
- string TypeName_Companion(Type type) {
+ string TypeName_Companion(Type type, TextWriter wr) {
Contract.Requires(type != null);
var udt = type as UserDefinedType;
if (udt != null && udt.ResolvedClass is TraitDecl) {
string s = udt.FullCompanionCompileName;
if (udt.TypeArgs.Count != 0) {
if (udt.TypeArgs.Exists(argType => argType is ObjectType)) {
- Error("compilation does not support type 'object' as a type parameter; consider introducing a ghost");
+ Error("compilation does not support type 'object' as a type parameter; consider introducing a ghost", wr);
}
- s += "<" + TypeNames(udt.TypeArgs) + ">";
+ s += "<" + TypeNames(udt.TypeArgs, wr) + ">";
}
return s;
} else {
- return TypeName(type);
+ return TypeName(type, wr);
}
}
- string TypeName(Type type)
+ string TypeName(Type type, TextWriter wr)
{
Contract.Requires(type != null);
Contract.Ensures(Contract.Result<string>() != null);
- type = type.NormalizeExpand();
- if (type is TypeProxy) {
+ var xType = type.NormalizeExpand();
+ if (xType is TypeProxy) {
// unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type
return "object";
}
- if (type is BoolType) {
+ if (xType is BoolType) {
return "bool";
- } else if (type is CharType) {
+ } else if (xType is CharType) {
return "char";
- } else if (type is IntType) {
+ } else if (xType is IntType) {
return "BigInteger";
- } else if (type is RealType) {
+ } else if (xType is RealType) {
return "Dafny.BigRational";
- } else if (type.AsNewtype != null) {
- NativeType nativeType = type.AsNewtype.NativeType;
+ } else if (xType.AsNewtype != null) {
+ NativeType nativeType = xType.AsNewtype.NativeType;
if (nativeType != null) {
return nativeType.Name;
}
- return TypeName(type.AsNewtype.BaseType);
- } else if (type is ObjectType) {
+ return TypeName(xType.AsNewtype.BaseType, wr);
+ } else if (xType is ObjectType) {
return "object";
- } else if (type.IsArrayType) {
- ArrayClassDecl at = type.AsArrayType;
+ } else if (xType.IsArrayType) {
+ ArrayClassDecl at = xType.AsArrayType;
Contract.Assert(at != null); // follows from type.IsArrayType
- Type elType = UserDefinedType.ArrayElementType(type);
- string name = TypeName(elType) + "[";
+ Type elType = UserDefinedType.ArrayElementType(xType);
+ string name = TypeName(elType, wr) + "[";
for (int i = 1; i < at.Dims; i++) {
name += ",";
}
return name + "]";
- } else if (type is UserDefinedType) {
- var udt = (UserDefinedType)type;
- return TypeName_UDT(udt.FullCompileName, udt.TypeArgs);
- } else if (type is SetType) {
- Type argType = ((SetType)type).Arg;
+ } else if (xType is UserDefinedType) {
+ var udt = (UserDefinedType)xType;
+ var s = udt.FullCompileName;
+ var rc = udt.ResolvedClass;
+ if (DafnyOptions.O.IronDafny &&
+ !(xType is ArrowType) &&
+ rc != null &&
+ rc.Module != null &&
+ !rc.Module.IsDefaultModule) {
+ while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) {
+ if (rc.ClonedFrom != null) {
+ rc = (TopLevelDecl)rc.ClonedFrom;
+ } else {
+ Contract.Assert(rc.ExclusiveRefinement != null);
+ rc = rc.ExclusiveRefinement;
+ }
+ }
+ s = rc.FullCompileName;
+ }
+ return TypeName_UDT(s, udt.TypeArgs, wr);
+ } else if (xType is SetType) {
+ Type argType = ((SetType)xType).Arg;
if (argType is ObjectType) {
- Error("compilation of set<object> is not supported; consider introducing a ghost");
+ Error("compilation of set<object> is not supported; consider introducing a ghost", wr);
}
- return DafnySetClass + "<" + TypeName(argType) + ">";
- } else if (type is SeqType) {
- Type argType = ((SeqType)type).Arg;
+ return DafnySetClass + "<" + TypeName(argType, wr) + ">";
+ } else if (xType is SeqType) {
+ Type argType = ((SeqType)xType).Arg;
if (argType is ObjectType) {
- Error("compilation of seq<object> is not supported; consider introducing a ghost");
+ Error("compilation of seq<object> is not supported; consider introducing a ghost", wr);
}
- return DafnySeqClass + "<" + TypeName(argType) + ">";
- } else if (type is MultiSetType) {
- Type argType = ((MultiSetType)type).Arg;
+ return DafnySeqClass + "<" + TypeName(argType, wr) + ">";
+ } else if (xType is MultiSetType) {
+ Type argType = ((MultiSetType)xType).Arg;
if (argType is ObjectType) {
- Error("compilation of seq<object> is not supported; consider introducing a ghost");
+ Error("compilation of seq<object> is not supported; consider introducing a ghost", wr);
}
- return DafnyMultiSetClass + "<" + TypeName(argType) + ">";
- } else if (type is MapType) {
- Type domType = ((MapType)type).Domain;
- Type ranType = ((MapType)type).Range;
+ return DafnyMultiSetClass + "<" + TypeName(argType, wr) + ">";
+ } else if (xType is MapType) {
+ Type domType = ((MapType)xType).Domain;
+ Type ranType = ((MapType)xType).Range;
if (domType is ObjectType || ranType is ObjectType) {
- Error("compilation of map<object, _> or map<_, object> is not supported; consider introducing a ghost");
+ Error("compilation of map<object, _> or map<_, object> is not supported; consider introducing a ghost", wr);
}
- return DafnyMapClass + "<" + TypeName(domType) + "," + TypeName(ranType) + ">";
+ return DafnyMapClass + "<" + TypeName(domType, wr) + "," + TypeName(ranType, wr) + ">";
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
}
}
- string TypeName_UDT(string fullCompileName, List<Type> typeArgs) {
+ string TypeName_UDT(string fullCompileName, List<Type> typeArgs, TextWriter wr) {
Contract.Requires(fullCompileName != null);
Contract.Requires(typeArgs != null);
string s = "@" + fullCompileName;
if (typeArgs.Count != 0) {
if (typeArgs.Exists(argType => argType is ObjectType)) {
- Error("compilation does not support type 'object' as a type parameter; consider introducing a ghost");
+ Error("compilation does not support type 'object' as a type parameter; consider introducing a ghost", wr);
}
- s += "<" + TypeNames(typeArgs) + ">";
+ s += "<" + TypeNames(typeArgs, wr) + ">";
}
return s;
}
- string/*!*/ TypeNames(List<Type/*!*/>/*!*/ types) {
+ string/*!*/ TypeNames(List<Type/*!*/>/*!*/ types, TextWriter wr) {
Contract.Requires(cce.NonNullElements(types));
Contract.Ensures(Contract.Result<string>() != null);
- return Util.Comma(types, TypeName);
+ string res = "";
+ string c = "";
+ foreach (var t in types) {
+ res += c + TypeName(t, wr);
+ c = ",";
+ }
+ return res;
}
string/*!*/ TypeParameters(List<TypeParameter/*!*/>/*!*/ targs) {
Contract.Requires(cce.NonNullElements(targs));
Contract.Ensures(Contract.Result<string>() != null);
- string s = "";
- string sep = "";
- foreach (TypeParameter tp in targs) {
- s += sep + "@" + tp.CompileName;
- sep = ",";
- }
- return s;
+ return Util.Comma(targs, tp => "@" + tp.CompileName);
}
- string DefaultValue(Type type)
+ string DefaultValue(Type type, TextWriter wr)
{
Contract.Requires(type != null);
Contract.Ensures(Contract.Result<string>() != null);
- type = type.NormalizeExpand();
- if (type is TypeProxy) {
+ var xType = type.NormalizeExpand();
+ if (xType is TypeProxy) {
// unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type
return "null";
}
- if (type is BoolType) {
+ if (xType is BoolType) {
return "false";
- } else if (type is CharType) {
+ } else if (xType is CharType) {
return "'D'";
- } else if (type is IntType) {
+ } else if (xType is IntType) {
return "BigInteger.Zero";
- } else if (type is RealType) {
+ } else if (xType is RealType) {
return "Dafny.BigRational.ZERO";
- } else if (type.AsNewtype != null) {
- if (type.AsNewtype.NativeType != null) {
+ } else if (xType.AsNewtype != null) {
+ if (xType.AsNewtype.NativeType != null) {
return "0";
}
- return DefaultValue(type.AsNewtype.BaseType);
- } else if (type.IsRefType) {
- return string.Format("({0})null", TypeName(type));
- } else if (type.IsDatatype) {
- UserDefinedType udt = (UserDefinedType)type;
- string s = "@" + udt.FullCompileName;
+ return DefaultValue(xType.AsNewtype.BaseType, wr);
+ } else if (xType.IsRefType) {
+ return string.Format("({0})null", TypeName(xType, wr));
+ } else if (xType.IsDatatype) {
+ var udt = (UserDefinedType)xType;
+ var s = "@" + udt.FullCompileName;
+ var rc = udt.ResolvedClass;
+ if (DafnyOptions.O.IronDafny &&
+ !(xType is ArrowType) &&
+ rc != null &&
+ rc.Module != null &&
+ !rc.Module.IsDefaultModule) {
+ while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) {
+ if (rc.ClonedFrom != null) {
+ rc = (TopLevelDecl)rc.ClonedFrom;
+ } else {
+ Contract.Assert(rc.ExclusiveRefinement != null);
+ rc = rc.ExclusiveRefinement;
+ }
+ }
+ s = "@" + rc.FullCompileName;
+ }
if (udt.TypeArgs.Count != 0) {
- s += "<" + TypeNames(udt.TypeArgs) + ">";
+ s += "<" + TypeNames(udt.TypeArgs, wr) + ">";
}
return string.Format("new {0}()", s);
- } else if (type.IsTypeParameter) {
- var udt = (UserDefinedType)type;
- return "default(@" + udt.FullCompileName + ")";
- } else if (type is SetType) {
- return DafnySetClass + "<" + TypeName(((SetType)type).Arg) + ">.Empty";
- } else if (type is MultiSetType) {
- return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)type).Arg) + ">.Empty";
- } else if (type is SeqType) {
- return DafnySeqClass + "<" + TypeName(((SeqType)type).Arg) + ">.Empty";
- } else if (type is MapType) {
- return TypeName(type)+".Empty";
- } else if (type is ArrowType) {
+ } else if (xType.IsTypeParameter) {
+ var udt = (UserDefinedType)xType;
+ string s = "default(@" + udt.FullCompileName;
+ if (udt.TypeArgs.Count != 0)
+ {
+ s += "<" + TypeNames(udt.TypeArgs, wr) + ">";
+ }
+ s += ")";
+ return s;
+ } else if (xType is SetType) {
+ return DafnySetClass + "<" + TypeName(((SetType)xType).Arg, wr) + ">.Empty";
+ } else if (xType is MultiSetType) {
+ return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)xType).Arg, wr) + ">.Empty";
+ } else if (xType is SeqType) {
+ return DafnySeqClass + "<" + TypeName(((SeqType)xType).Arg, wr) + ">.Empty";
+ } else if (xType is MapType) {
+ return TypeName(xType, wr) + ".Empty";
+ } else if (xType is ArrowType) {
return "null";
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
@@ -1137,59 +1371,61 @@ namespace Microsoft.Dafny {
public class CheckHasNoAssumes_Visitor : BottomUpVisitor
{
readonly Compiler compiler;
- public CheckHasNoAssumes_Visitor(Compiler c) {
+ TextWriter wr;
+ public CheckHasNoAssumes_Visitor(Compiler c, TextWriter wr) {
Contract.Requires(c != null);
compiler = c;
+ this.wr = wr;
}
protected override void VisitOneStmt(Statement stmt) {
if (stmt is AssumeStmt) {
- compiler.Error("an assume statement cannot be compiled (line {0})", stmt.Tok.line);
+ compiler.Error("an assume statement cannot be compiled (line {0})", wr, stmt.Tok.line);
} else if (stmt is AssignSuchThatStmt) {
var s = (AssignSuchThatStmt)stmt;
if (s.AssumeToken != null) {
- compiler.Error("an assume statement cannot be compiled (line {0})", s.AssumeToken.line);
+ compiler.Error("an assume statement cannot be compiled (line {0})", wr, s.AssumeToken.line);
}
} else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
if (s.Body == null) {
- compiler.Error("a forall statement without a body cannot be compiled (line {0})", stmt.Tok.line);
+ compiler.Error("a forall statement without a body cannot be compiled (line {0})", wr, stmt.Tok.line);
}
} else if (stmt is WhileStmt) {
var s = (WhileStmt)stmt;
if (s.Body == null) {
- compiler.Error("a while statement without a body cannot be compiled (line {0})", stmt.Tok.line);
+ compiler.Error("a while statement without a body cannot be compiled (line {0})", wr, stmt.Tok.line);
}
}
}
}
- void TrStmt(Statement stmt, int indent)
+ TextWriter TrStmt(Statement stmt, int indent)
{
Contract.Requires(stmt != null);
+ TextWriter wr = new StringWriter();
if (stmt.IsGhost) {
- var v = new CheckHasNoAssumes_Visitor(this);
+ var v = new CheckHasNoAssumes_Visitor(this, wr);
v.Visit(stmt);
- Indent(indent); wr.WriteLine("{ }");
- return;
+ Indent(indent, wr); wr.WriteLine("{ }");
+ return wr;
}
-
if (stmt is PrintStmt) {
PrintStmt s = (PrintStmt)stmt;
foreach (var arg in s.Args) {
- Indent(indent);
+ Indent(indent, wr);
wr.Write("System.Console.Write(");
- TrExpr(arg);
+ TrExpr(arg, wr, false);
wr.WriteLine(");");
}
} else if (stmt is BreakStmt) {
var s = (BreakStmt)stmt;
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("goto after_{0};", s.TargetStmt.Labels.Data.AssignUniqueId("after_", idGenerator));
} else if (stmt is ProduceStmt) {
var s = (ProduceStmt)stmt;
if (s.hiddenUpdate != null)
- TrStmt(s.hiddenUpdate, indent);
- Indent(indent);
+ wr.Write(TrStmt(s.hiddenUpdate, indent).ToString());
+ Indent(indent, wr);
if (s is YieldStmt) {
wr.WriteLine("yield return null;");
} else {
@@ -1199,7 +1435,7 @@ namespace Microsoft.Dafny {
var s = (UpdateStmt)stmt;
var resolved = s.ResolvedStatements;
if (resolved.Count == 1) {
- TrStmt(resolved[0], indent);
+ wr.Write(TrStmt(resolved[0], indent).ToString());
} else {
// multi-assignment
Contract.Assert(s.Lhss.Count == resolved.Count);
@@ -1211,17 +1447,17 @@ namespace Microsoft.Dafny {
var lhs = s.Lhss[i];
var rhs = s.Rhss[i];
if (!(rhs is HavocRhs)) {
- lvalues.Add(CreateLvalue(lhs, indent));
+ lvalues.Add(CreateLvalue(lhs, indent, wr));
string target = idGenerator.FreshId("_rhs");
rhss.Add(target);
- TrRhs("var " + target, null, rhs, indent);
+ TrRhs("var " + target, null, rhs, indent, wr);
}
}
}
Contract.Assert(lvalues.Count == rhss.Count);
for (int i = 0; i < lvalues.Count; i++) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("{0} = {1};", lvalues[i], rhss[i]);
}
}
@@ -1229,32 +1465,32 @@ namespace Microsoft.Dafny {
} else if (stmt is AssignStmt) {
AssignStmt s = (AssignStmt)stmt;
Contract.Assert(!(s.Lhs is SeqSelectExpr) || ((SeqSelectExpr)s.Lhs).SelectOne); // multi-element array assignments are not allowed
- TrRhs(null, s.Lhs, s.Rhs, indent);
+ TrRhs(null, s.Lhs, s.Rhs, indent, wr);
} else if (stmt is AssignSuchThatStmt) {
var s = (AssignSuchThatStmt)stmt;
if (s.AssumeToken != null) {
// Note, a non-ghost AssignSuchThatStmt may contain an assume
- Error("an assume statement cannot be compiled (line {0})", s.AssumeToken.line);
+ Error("an assume statement cannot be compiled (line {0})", wr, s.AssumeToken.line);
} else if (s.MissingBounds != null) {
foreach (var bv in s.MissingBounds) {
- Error("this assign-such-that statement is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", bv.Name, s.Tok.line);
+ Error("this assign-such-that statement is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", wr, bv.Name, s.Tok.line);
}
} else {
Contract.Assert(s.Bounds != null); // follows from s.MissingBounds == null
TrAssignSuchThat(indent,
s.Lhss.ConvertAll(lhs => ((IdentifierExpr)lhs.Resolved).Var), // the resolver allows only IdentifierExpr left-hand sides
- s.Expr, s.Bounds, s.Tok.line);
+ s.Expr, s.Bounds, s.Tok.line, wr, false);
}
} else if (stmt is CallStmt) {
CallStmt s = (CallStmt)stmt;
- TrCallStmt(s, null, indent);
+ wr.Write(TrCallStmt(s, null, indent).ToString());
} else if (stmt is BlockStmt) {
- Indent(indent); wr.WriteLine("{");
- TrStmtList(((BlockStmt)stmt).Body, indent);
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("{");
+ TrStmtList(((BlockStmt)stmt).Body, indent, wr);
+ Indent(indent, wr); wr.WriteLine("}");
} else if (stmt is IfStmt) {
IfStmt s = (IfStmt)stmt;
@@ -1263,37 +1499,45 @@ namespace Microsoft.Dafny {
if (s.Els == null) {
// let's compile the "else" branch, since that involves no work
// (still, let's leave a marker in the source code to indicate that this is what we did)
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("if (!false) { }");
} else {
// let's compile the "then" branch
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("if (true)");
- TrStmt(s.Thn, indent);
+ wr.Write(TrStmt(s.Thn, indent).ToString());
}
} else {
- Indent(indent); wr.Write("if (");
- TrExpr(s.Guard);
+ Indent(indent, wr); wr.Write("if (");
+ TrExpr(s.IsExistentialGuard ? Translator.AlphaRename((ExistsExpr)s.Guard, "eg_d", new Translator(null)) : s.Guard, wr, false);
wr.WriteLine(")");
- TrStmt(s.Thn, indent);
+ // We'd like to do "TrStmt(s.Thn, indent)", except we want the scope of any existential variables to come inside the block
+ Indent(indent, wr); wr.WriteLine("{");
+ if (s.IsExistentialGuard) {
+ IntroduceAndAssignBoundVars(indent + IndentAmount, (ExistsExpr)s.Guard, wr);
+ }
+ TrStmtList(s.Thn.Body, indent, wr);
+ Indent(indent, wr); wr.WriteLine("}");
+
if (s.Els != null) {
- Indent(indent); wr.WriteLine("else");
- TrStmt(s.Els, indent);
+ Indent(indent, wr); wr.WriteLine("else");
+ wr.Write(TrStmt(s.Els, indent).ToString());
}
}
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
- foreach (var alternative in s.Alternatives) {
- }
- Indent(indent);
+ Indent(indent, wr);
foreach (var alternative in s.Alternatives) {
wr.Write("if (");
- TrExpr(alternative.Guard);
+ TrExpr(alternative.IsExistentialGuard ? Translator.AlphaRename((ExistsExpr)alternative.Guard, "eg_d", new Translator(null)) : alternative.Guard, wr, false);
wr.WriteLine(") {");
- TrStmtList(alternative.Body, indent);
- Indent(indent);
+ if (alternative.IsExistentialGuard) {
+ IntroduceAndAssignBoundVars(indent + IndentAmount, (ExistsExpr)alternative.Guard, wr);
+ }
+ TrStmtList(alternative.Body, indent, wr);
+ Indent(indent, wr);
wr.Write("} else ");
}
wr.WriteLine("{ /*unreachable alternative*/ }");
@@ -1301,38 +1545,38 @@ namespace Microsoft.Dafny {
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
if (s.Body == null) {
- return;
+ return wr;
}
if (s.Guard == null) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("while (false) { }");
} else {
- Indent(indent);
+ Indent(indent, wr);
wr.Write("while (");
- TrExpr(s.Guard);
+ TrExpr(s.Guard, wr, false);
wr.WriteLine(")");
- TrStmt(s.Body, indent);
+ wr.Write(TrStmt(s.Body, indent).ToString());
}
} else if (stmt is AlternativeLoopStmt) {
var s = (AlternativeLoopStmt)stmt;
if (s.Alternatives.Count != 0) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("while (true) {");
int ind = indent + IndentAmount;
foreach (var alternative in s.Alternatives) {
}
- Indent(ind);
+ Indent(ind, wr);
foreach (var alternative in s.Alternatives) {
wr.Write("if (");
- TrExpr(alternative.Guard);
+ TrExpr(alternative.Guard, wr, false);
wr.WriteLine(") {");
- TrStmtList(alternative.Body, ind);
- Indent(ind);
+ TrStmtList(alternative.Body, ind, wr);
+ Indent(ind, wr);
wr.Write("} else ");
}
wr.WriteLine("{ break; }");
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("}");
}
@@ -1340,17 +1584,17 @@ namespace Microsoft.Dafny {
var s = (ForallStmt)stmt;
if (s.Kind != ForallStmt.ParBodyKind.Assign) {
// Call and Proof have no side effects, so they can simply be optimized away.
- return;
+ return wr;
} else if (s.BoundVars.Count == 0) {
// the bound variables just spell out a single point, so the forall statement is equivalent to one execution of the body
- TrStmt(s.Body, indent);
- return;
+ wr.Write(TrStmt(s.Body, indent).ToString());
+ return wr;
}
var s0 = (AssignStmt)s.S0;
if (s0.Rhs is HavocRhs) {
// The forall statement says to havoc a bunch of things. This can be efficiently compiled
// into doing nothing.
- return;
+ return wr;
}
var rhs = ((ExprRhs)s0.Rhs).Expr;
@@ -1394,29 +1638,29 @@ namespace Microsoft.Dafny {
if (s0.Lhs is MemberSelectExpr) {
var lhs = (MemberSelectExpr)s0.Lhs;
L = 2;
- tupleTypeArgs = TypeName(lhs.Obj.Type);
+ tupleTypeArgs = TypeName(lhs.Obj.Type, wr);
} else if (s0.Lhs is SeqSelectExpr) {
var lhs = (SeqSelectExpr)s0.Lhs;
L = 3;
// note, we might as well do the BigInteger-to-int cast for array indices here, before putting things into the Tuple rather than when they are extracted from the Tuple
- tupleTypeArgs = TypeName(lhs.Seq.Type) + ",int";
+ tupleTypeArgs = TypeName(lhs.Seq.Type, wr) + ",int";
} else {
var lhs = (MultiSelectExpr)s0.Lhs;
L = 2 + lhs.Indices.Count;
if (8 < L) {
- Error("compiler currently does not support assignments to more-than-6-dimensional arrays in forall statements");
- return;
+ Error("compiler currently does not support assignments to more-than-6-dimensional arrays in forall statements", wr);
+ return wr;
}
- tupleTypeArgs = TypeName(lhs.Array.Type);
+ tupleTypeArgs = TypeName(lhs.Array.Type, wr);
for (int i = 0; i < lhs.Indices.Count; i++) {
// note, we might as well do the BigInteger-to-int cast for array indices here, before putting things into the Tuple rather than when they are extracted from the Tuple
tupleTypeArgs += ",int";
}
}
- tupleTypeArgs += "," + TypeName(rhs.Type);
+ tupleTypeArgs += "," + TypeName(rhs.Type, wr);
// declare and construct "ingredients"
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("var {0} = new System.Collections.Generic.List<System.Tuple<{1}>>();", ingredients, tupleTypeArgs);
var n = s.BoundVars.Count;
@@ -1426,31 +1670,38 @@ namespace Microsoft.Dafny {
var bound = s.Bounds[i];
var bv = s.BoundVars[i];
if (bound is ComprehensionExpr.BoolBoundedPool) {
- Indent(ind);
+ Indent(ind, wr);
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ Indent(ind, wr);
+ wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName);
} else if (bound is ComprehensionExpr.IntBoundedPool) {
var b = (ComprehensionExpr.IntBoundedPool)bound;
- Indent(ind);
- wr.Write("for (var @{0} = ", bv.CompileName);
- TrExpr(b.LowerBound);
- wr.Write("; @{0} < ", bv.CompileName);
- TrExpr(b.UpperBound);
- wr.Write("; @{0}++) {{ ", bv.CompileName);
+ Indent(ind, wr);
+ if (AsNativeType(bv.Type) != null) {
+ wr.Write("foreach (var @{0} in @{1}.IntegerRange(", bv.CompileName, bv.Type.AsNewtype.FullCompileName);
+ } else {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", bv.CompileName);
+ }
+ TrExpr(b.LowerBound, wr, false);
+ wr.Write(", ");
+ TrExpr(b.UpperBound, wr, false);
+ wr.Write(")) { ");
} else if (bound is ComprehensionExpr.SetBoundedPool) {
var b = (ComprehensionExpr.SetBoundedPool)bound;
- Indent(ind);
+ Indent(ind, wr);
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Set);
+ TrExpr(b.Set, wr, false);
wr.Write(").Elements) { ");
} else if (bound is ComprehensionExpr.SeqBoundedPool) {
var b = (ComprehensionExpr.SeqBoundedPool)bound;
- Indent(ind);
+ Indent(ind, wr);
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Seq);
+ TrExpr(b.Seq, wr, false);
wr.Write(").UniqueElements) { ");
} else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
- wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type));
+ wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type, wr));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
}
@@ -1460,55 +1711,55 @@ namespace Microsoft.Dafny {
// if (range) {
// ingredients.Add(new L-Tuple( LHS0(w,x,y,z), LHS1(w,x,y,z), ..., RHS(w,x,y,z) ));
// }
- Indent(indent + n * IndentAmount);
+ Indent(indent + n * IndentAmount, wr);
wr.Write("if (");
foreach (var bv in s.BoundVars) {
if (bv.Type.NormalizeExpand() is NatType) {
wr.Write("0 <= {0} && ", bv.CompileName);
}
}
- TrExpr(s.Range);
+ TrExpr(s.Range, wr, false);
wr.WriteLine(") {");
var indFinal = indent + (n + 1) * IndentAmount;
- Indent(indFinal);
+ Indent(indFinal, wr);
wr.Write("{0}.Add(new System.Tuple<{1}>(", ingredients, tupleTypeArgs);
if (s0.Lhs is MemberSelectExpr) {
var lhs = (MemberSelectExpr)s0.Lhs;
- TrExpr(lhs.Obj);
+ TrExpr(lhs.Obj, wr, false);
} else if (s0.Lhs is SeqSelectExpr) {
var lhs = (SeqSelectExpr)s0.Lhs;
- TrExpr(lhs.Seq);
+ TrExpr(lhs.Seq, wr, false);
wr.Write(", (int)(");
- TrExpr(lhs.E0);
+ TrExpr(lhs.E0, wr, false);
wr.Write(")");
} else {
var lhs = (MultiSelectExpr)s0.Lhs;
- TrExpr(lhs.Array);
+ TrExpr(lhs.Array, wr, false);
for (int i = 0; i < lhs.Indices.Count; i++) {
wr.Write(", (int)(");
- TrExpr(lhs.Indices[i]);
+ TrExpr(lhs.Indices[i], wr, false);
wr.Write(")");
}
}
wr.Write(", ");
- TrExpr(rhs);
+ TrExpr(rhs, wr, false);
wr.WriteLine("));");
- Indent(indent + n * IndentAmount);
+ Indent(indent + n * IndentAmount, wr);
wr.WriteLine("}");
for (int i = n; 0 <= --i; ) {
- Indent(indent + i * IndentAmount);
+ Indent(indent + i * IndentAmount, wr);
wr.WriteLine("}");
}
// foreach (L-Tuple l in ingredients) {
// LHS[ l0, l1, l2, ..., l(L-2) ] = l(L-1);
// }
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("foreach (var {0} in {1}) {{", tup, ingredients);
- Indent(indent + IndentAmount);
+ Indent(indent + IndentAmount, wr);
if (s0.Lhs is MemberSelectExpr) {
var lhs = (MemberSelectExpr)s0.Lhs;
wr.WriteLine("{0}.Item1.@{1} = {0}.Item2;", tup, lhs.MemberName);
@@ -1525,7 +1776,7 @@ namespace Microsoft.Dafny {
}
wr.WriteLine("] = {0}.Item{1};", tup, L);
}
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("}");
} else if (stmt is MatchStmt) {
@@ -1542,42 +1793,64 @@ namespace Microsoft.Dafny {
// }
if (s.Cases.Count != 0) {
string source = idGenerator.FreshId("_source");
- Indent(indent);
- wr.Write("{0} {1} = ", TypeName(cce.NonNull(s.Source.Type)), source);
- TrExpr(s.Source);
+ Indent(indent, wr);
+ wr.Write("{0} {1} = ", TypeName(cce.NonNull(s.Source.Type), wr), source);
+ TrExpr(s.Source, wr, false);
wr.WriteLine(";");
int i = 0;
var sourceType = (UserDefinedType)s.Source.Type.NormalizeExpand();
foreach (MatchCaseStmt mc in s.Cases) {
- MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, s.Cases.Count, indent);
- TrStmtList(mc.Body, indent);
+ MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, s.Cases.Count, indent, wr);
+ TrStmtList(mc.Body, indent, wr);
i++;
}
- Indent(indent); wr.WriteLine("}");
+ Indent(indent, wr); wr.WriteLine("}");
}
} else if (stmt is VarDeclStmt) {
var s = (VarDeclStmt)stmt;
foreach (var local in s.Locals) {
- TrLocalVar(local, true, indent);
+ TrLocalVar(local, true, indent, wr);
}
if (s.Update != null) {
- TrStmt(s.Update, indent);
+ wr.Write(TrStmt(s.Update, indent).ToString());
}
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
+ for (int i = 0; i < s.LHSs.Count; i++) {
+ var lhs = s.LHSs[i];
+ if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) {
+ TrCasePatternOpt(lhs, s.RHSs[i], null, indent, wr, false);
+ }
+ }
} else if (stmt is ModifyStmt) {
var s = (ModifyStmt)stmt;
if (s.Body != null) {
- TrStmt(s.Body, indent);
+ wr.Write(TrStmt(s.Body, indent).ToString());
}
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
}
+
+ return wr;
}
- private void TrAssignSuchThat(int indent, List<IVariable> lhss, Expression constraint, List<ComprehensionExpr.BoundedPool> bounds, int debuginfoLine) {
+ private void IntroduceAndAssignBoundVars(int indent, ExistsExpr exists, TextWriter wr) {
+ Contract.Requires(0 <= indent);
+ Contract.Requires(exists != null);
+ Contract.Assume(exists.Bounds != null); // follows from successful resolution
+ Contract.Assert(exists.Range == null); // follows from invariant of class IfStmt
+ foreach (var bv in exists.BoundVars) {
+ TrLocalVar(bv, false, indent, wr);
+ }
+ var ivars = exists.BoundVars.ConvertAll(bv => (IVariable)bv);
+ TrAssignSuchThat(indent, ivars, exists.Term, exists.Bounds, exists.tok.line, wr, false);
+ }
+
+ private void TrAssignSuchThat(int indent, List<IVariable> lhss, Expression constraint, List<ComprehensionExpr.BoundedPool> bounds, int debuginfoLine, TextWriter wr, bool inLetExprBody) {
Contract.Requires(0 <= indent);
Contract.Requires(lhss != null);
Contract.Requires(constraint != null);
@@ -1619,7 +1892,7 @@ namespace Microsoft.Dafny {
int ind = indent;
bool needIterLimit = lhss.Count != 1 && bounds.Exists(bnd => !bnd.IsFinite);
if (needIterLimit) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("for (var {0} = new BigInteger(5); ; {0} *= 2) {{", iterLimit);
ind += IndentAmount;
}
@@ -1628,89 +1901,87 @@ namespace Microsoft.Dafny {
var bound = bounds[i];
var bv = lhss[i];
if (needIterLimit) {
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("var {0}_{1} = {0};", iterLimit, i);
}
var tmpVar = idGenerator.FreshId("_assign_such_that_");
- Indent(ind);
+ Indent(ind, wr);
if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.WriteLine("foreach (var {0} in Dafny.Helpers.AllBooleans) {{ @{1} = {0};", tmpVar, bv.CompileName);
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ wr.WriteLine("foreach (var {0} in Dafny.Helpers.AllChars) {{ @{1} = {0};", tmpVar, bv.CompileName);
} else if (bound is ComprehensionExpr.IntBoundedPool) {
var b = (ComprehensionExpr.IntBoundedPool)bound;
- // (tmpVar is not used in this case)
- if (b.LowerBound != null) {
- wr.Write("@{0} = ", bv.CompileName);
- TrExpr(b.LowerBound);
- wr.WriteLine(";");
- Indent(ind);
- if (b.UpperBound != null) {
- wr.Write("for (; @{0} < ", bv.CompileName);
- TrExpr(b.UpperBound);
- wr.WriteLine("; @{0}++) {{ ", bv.CompileName);
- } else {
- wr.WriteLine("for (;; @{0}++) {{ ", bv.CompileName);
- }
+ if (AsNativeType(bv.Type) != null) {
+ wr.Write("foreach (var @{0} in @{1}.IntegerRange(", tmpVar, bv.Type.AsNewtype.FullCompileName);
} else {
- Contract.Assert(b.UpperBound != null);
- wr.Write("@{0} = ", bv.CompileName);
- TrExpr(b.UpperBound);
- wr.WriteLine(";");
- Indent(ind);
- wr.WriteLine("for (;; @{0}--) {{ ", bv.CompileName);
+ wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", tmpVar);
+ }
+ if (b.LowerBound == null) {
+ wr.Write("null");
+ } else {
+ TrExpr(b.LowerBound, wr, inLetExprBody);
+ }
+ wr.Write(", ");
+ if (b.UpperBound == null) {
+ wr.Write("null");
+ } else {
+ TrExpr(b.UpperBound, wr, inLetExprBody);
}
+ wr.WriteLine(")) {{ @{1} = {0};", tmpVar, bv.CompileName);
} else if (bound is AssignSuchThatStmt.WiggleWaggleBound) {
wr.WriteLine("foreach (var {0} in Dafny.Helpers.AllIntegers) {{ @{1} = {0};", tmpVar, bv.CompileName);
} else if (bound is ComprehensionExpr.SetBoundedPool) {
var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("foreach (var {0} in (", tmpVar);
- TrExpr(b.Set);
+ TrExpr(b.Set, wr, inLetExprBody);
wr.WriteLine(").Elements) {{ @{0} = {1};", bv.CompileName, tmpVar);
} else if (bound is ComprehensionExpr.SubSetBoundedPool) {
var b = (ComprehensionExpr.SubSetBoundedPool)bound;
wr.Write("foreach (var {0} in (", tmpVar);
- TrExpr(b.UpperBound);
+ TrExpr(b.UpperBound, wr, inLetExprBody);
wr.WriteLine(").AllSubsets) {{ @{0} = {1};", bv.CompileName, tmpVar);
} else if (bound is ComprehensionExpr.MapBoundedPool) {
var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("foreach (var {0} in (", tmpVar);
- TrExpr(b.Map);
+ TrExpr(b.Map, wr, inLetExprBody);
wr.WriteLine(").Domain) {{ @{0} = {1};", bv.CompileName, tmpVar);
} else if (bound is ComprehensionExpr.SeqBoundedPool) {
var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("foreach (var {0} in (", tmpVar);
- TrExpr(b.Seq);
+ TrExpr(b.Seq, wr, inLetExprBody);
wr.WriteLine(").Elements) {{ @{0} = {1};", bv.CompileName, tmpVar);
} else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
- wr.WriteLine("foreach (var {0} in {1}.AllSingletonConstructors) {{ @{2} = {0};", tmpVar, TypeName(bv.Type), bv.CompileName);
+ wr.WriteLine("foreach (var {0} in {1}.AllSingletonConstructors) {{ @{2} = {0};", tmpVar, TypeName(bv.Type, wr), bv.CompileName);
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
}
if (needIterLimit) {
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("if ({0}_{1} == 0) {{ break; }} {0}_{1}--;", iterLimit, i);
}
}
- Indent(ind);
+ Indent(ind, wr);
wr.Write("if (");
- TrExpr(constraint);
+ TrExpr(constraint, wr, inLetExprBody);
wr.WriteLine(") {");
- Indent(ind + IndentAmount);
+ Indent(ind + IndentAmount, wr);
wr.WriteLine("goto {0};", doneLabel);
- Indent(ind);
+ Indent(ind, wr);
wr.WriteLine("}");
- Indent(indent);
+ Indent(indent, wr);
for (int i = 0; i < n; i++) {
wr.Write(i == 0 ? "}" : " }");
}
wr.WriteLine(needIterLimit ? " }" : "");
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("throw new System.Exception(\"assign-such-that search produced no value (line {0})\");", debuginfoLine);
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("{0}: ;", doneLabel);
}
- string CreateLvalue(Expression lhs, int indent) {
+ string CreateLvalue(Expression lhs, int indent, TextWriter wr) {
lhs = lhs.Resolved;
if (lhs is IdentifierExpr) {
var ll = (IdentifierExpr)lhs;
@@ -1718,9 +1989,9 @@ namespace Microsoft.Dafny {
} else if (lhs is MemberSelectExpr) {
var ll = (MemberSelectExpr)lhs;
string obj = idGenerator.FreshId("_obj");
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", obj);
- TrExpr(ll.Obj);
+ TrExpr(ll.Obj, wr, false);
wr.WriteLine(";");
return string.Format("{0}.@{1}", obj, ll.Member.CompileName);
} else if (lhs is SeqSelectExpr) {
@@ -1728,31 +1999,31 @@ namespace Microsoft.Dafny {
var c = idGenerator.FreshNumericId("_arr+_index");
string arr = "_arr" + c;
string index = "_index" + c;
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", arr);
- TrExpr(ll.Seq);
+ TrExpr(ll.Seq, wr, false);
wr.WriteLine(";");
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", index);
- TrExpr(ll.E0);
+ TrExpr(ll.E0, wr, false);
wr.WriteLine(";");
return string.Format("{0}[(int){1}]", arr, index);
} else {
var ll = (MultiSelectExpr)lhs;
var c = idGenerator.FreshNumericId("_arr+_index");
string arr = "_arr" + c;
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", arr);
- TrExpr(ll.Array);
+ TrExpr(ll.Array, wr, false);
wr.WriteLine(";");
string fullString = arr + "[";
string sep = "";
int i = 0;
foreach (var idx in ll.Indices) {
string index = "_index" + i + "_" + c;
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", index);
- TrExpr(idx);
+ TrExpr(idx, wr, false);
wr.WriteLine(";");
fullString += sep + "(int)" + index;
sep = ", ";
@@ -1762,21 +2033,21 @@ namespace Microsoft.Dafny {
}
}
- void TrRhs(string target, Expression targetExpr, AssignmentRhs rhs, int indent) {
+ void TrRhs(string target, Expression targetExpr, AssignmentRhs rhs, int indent, TextWriter wr) {
Contract.Requires((target == null) != (targetExpr == null));
var tRhs = rhs as TypeRhs;
if (tRhs != null && tRhs.InitCall != null) {
string nw = idGenerator.FreshId("_nw");
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", nw);
- TrAssignmentRhs(rhs); // in this case, this call will not require us to spill any let variables first
+ TrAssignmentRhs(rhs, wr); // in this case, this call will not require us to spill any let variables first
wr.WriteLine(";");
- TrCallStmt(tRhs.InitCall, nw, indent);
- Indent(indent);
+ wr.Write(TrCallStmt(tRhs.InitCall, nw, indent).ToString());
+ Indent(indent, wr);
if (target != null) {
wr.Write(target);
} else {
- TrExpr(targetExpr);
+ TrExpr(targetExpr, wr, false);
}
wr.WriteLine(" = {0};", nw);
} else if (rhs is HavocRhs) {
@@ -1787,22 +2058,23 @@ namespace Microsoft.Dafny {
foreach (Expression dim in tRhs.ArrayDimensions) {
}
}
- Indent(indent);
+ Indent(indent, wr);
if (target != null) {
wr.Write(target);
} else {
- TrExpr(targetExpr);
+ TrExpr(targetExpr, wr, false);
}
wr.Write(" = ");
- TrAssignmentRhs(rhs);
+ TrAssignmentRhs(rhs, wr);
wr.WriteLine(";");
}
}
- void TrCallStmt(CallStmt s, string receiverReplacement, int indent) {
+ TextWriter TrCallStmt(CallStmt s, string receiverReplacement, int indent) {
Contract.Requires(s != null);
Contract.Assert(s.Method != null); // follows from the fact that stmt has been successfully resolved
+ StringWriter wr = new StringWriter();
if (s.Method == enclosingMethod && enclosingMethod.IsTailRecursive) {
// compile call as tail-recursive
@@ -1819,9 +2091,9 @@ namespace Microsoft.Dafny {
string inTmp = idGenerator.FreshId("_in");
inTmps.Add(inTmp);
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", inTmp);
- TrExpr(s.Receiver);
+ TrExpr(s.Receiver, wr, false);
wr.WriteLine(";");
}
for (int i = 0; i < s.Method.Ins.Count; i++) {
@@ -1829,29 +2101,29 @@ namespace Microsoft.Dafny {
if (!p.IsGhost) {
string inTmp = idGenerator.FreshId("_in");
inTmps.Add(inTmp);
- Indent(indent);
+ Indent(indent, wr);
wr.Write("var {0} = ", inTmp);
- TrExpr(s.Args[i]);
+ TrExpr(s.Args[i], wr, false);
wr.WriteLine(";");
}
}
// Now, assign to the formals
int n = 0;
if (!s.Method.IsStatic) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("_this = {0};", inTmps[n]);
n++;
}
foreach (var p in s.Method.Ins) {
if (!p.IsGhost) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("{0} = {1};", p.CompileName, inTmps[n]);
n++;
}
}
Contract.Assert(n == inTmps.Count);
// finally, the jump back to the head of the method
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("goto TAIL_CALL_START;");
} else {
@@ -1862,7 +2134,7 @@ namespace Microsoft.Dafny {
for (int i = 0; i < s.Method.Outs.Count; i++) {
Formal p = s.Method.Outs[i];
if (!p.IsGhost) {
- lvalues.Add(CreateLvalue(s.Lhs[i], indent));
+ lvalues.Add(CreateLvalue(s.Lhs[i], indent, wr));
}
}
var outTmps = new List<string>();
@@ -1871,8 +2143,8 @@ namespace Microsoft.Dafny {
if (!p.IsGhost) {
string target = idGenerator.FreshId("_out");
outTmps.Add(target);
- Indent(indent);
- wr.WriteLine("{0} {1};", TypeName(s.Lhs[i].Type), target);
+ Indent(indent, wr);
+ wr.WriteLine("{0} {1};", TypeName(s.Lhs[i].Type, wr), target);
}
}
Contract.Assert(lvalues.Count == outTmps.Count);
@@ -1883,14 +2155,14 @@ namespace Microsoft.Dafny {
}
}
if (receiverReplacement != null) {
- Indent(indent);
+ Indent(indent, wr);
wr.Write("@" + receiverReplacement);
} else if (s.Method.IsStatic) {
- Indent(indent);
- wr.Write(TypeName_Companion(s.Receiver.Type));
+ Indent(indent, wr);
+ wr.Write(TypeName_Companion(s.Receiver.Type, wr));
} else {
- Indent(indent);
- TrParenExpr(s.Receiver);
+ Indent(indent, wr);
+ TrParenExpr(s.Receiver, wr, false);
}
wr.Write(".@{0}(", s.Method.CompileName);
@@ -1899,7 +2171,7 @@ namespace Microsoft.Dafny {
Formal p = s.Method.Ins[i];
if (!p.IsGhost) {
wr.Write(sep);
- TrExpr(s.Args[i]);
+ TrExpr(s.Args[i], wr, false);
sep = ", ";
}
}
@@ -1912,44 +2184,45 @@ namespace Microsoft.Dafny {
// assign to the actual LHSs
for (int j = 0; j < lvalues.Count; j++) {
- Indent(indent);
+ Indent(indent, wr);
wr.WriteLine("{0} = {1};", lvalues[j], outTmps[j]);
}
}
+ return wr;
}
/// <summary>
/// Before calling TrAssignmentRhs(rhs), the caller must have spilled the let variables declared in "rhs".
/// </summary>
- void TrAssignmentRhs(AssignmentRhs rhs) {
+ void TrAssignmentRhs(AssignmentRhs rhs, TextWriter wr) {
Contract.Requires(rhs != null);
Contract.Requires(!(rhs is HavocRhs));
if (rhs is ExprRhs) {
ExprRhs e = (ExprRhs)rhs;
- TrExpr(e.Expr);
+ TrExpr(e.Expr, wr, false);
} else {
TypeRhs tp = (TypeRhs)rhs;
if (tp.ArrayDimensions == null) {
- wr.Write("new {0}()", TypeName(tp.EType));
+ wr.Write("new {0}()", TypeName(tp.EType, wr));
} else {
if (tp.EType.IsIntegerType || tp.EType.IsTypeParameter) {
// Because the default constructor for BigInteger does not generate a valid BigInteger, we have
// to excplicitly initialize the elements of an integer array. This is all done in a helper routine.
- wr.Write("Dafny.Helpers.InitNewArray{0}<{1}>", tp.ArrayDimensions.Count, TypeName(tp.EType));
+ wr.Write("Dafny.Helpers.InitNewArray{0}<{1}>", tp.ArrayDimensions.Count, TypeName(tp.EType, wr));
string prefix = "(";
foreach (Expression dim in tp.ArrayDimensions) {
wr.Write(prefix);
- TrParenExpr(dim);
+ TrParenExpr(dim, wr, false);
prefix = ", ";
}
wr.Write(")");
} else {
- wr.Write("new {0}", TypeName(tp.EType));
+ wr.Write("new {0}", TypeName(tp.EType, wr));
string prefix = "[";
foreach (Expression dim in tp.ArrayDimensions) {
wr.Write("{0}(int)", prefix);
- TrParenExpr(dim);
+ TrParenExpr(dim, wr, false);
prefix = ", ";
}
wr.Write("]");
@@ -1958,34 +2231,43 @@ namespace Microsoft.Dafny {
}
}
- void TrStmtList(List<Statement/*!*/>/*!*/ stmts, int indent) {Contract.Requires(cce.NonNullElements(stmts));
+ void TrStmtList(List<Statement/*!*/>/*!*/ stmts, int indent, TextWriter writer) {Contract.Requires(cce.NonNullElements(stmts));
foreach (Statement ss in stmts) {
- TrStmt(ss, indent + IndentAmount);
+ copyInstrWriter.Clear();
+ TextWriter wr = TrStmt(ss, indent + IndentAmount);
+ // write out any copy instructions that copies the out param
+ // used in letexpr to a local
+ string copyInstr = copyInstrWriter.ToString();
+ if (copyInstr != "") {
+ Indent(indent + IndentAmount, writer);
+ writer.Write(copyInstrWriter.ToString());
+ }
+ writer.Write(wr.ToString());
if (ss.Labels != null) {
- Indent(indent); // labels are not indented as much as the statements
- wr.WriteLine("after_{0}: ;", ss.Labels.Data.AssignUniqueId("after_", idGenerator));
+ Indent(indent, writer); // labels are not indented as much as the statements
+ writer.WriteLine("after_{0}: ;", ss.Labels.Data.AssignUniqueId("after_", idGenerator));
}
}
}
- void TrLocalVar(LocalVariable s, bool alwaysInitialize, int indent) {
- Contract.Requires(s != null);
- if (s.IsGhost) {
+ void TrLocalVar(IVariable v, bool alwaysInitialize, int indent, TextWriter wr) {
+ Contract.Requires(v != null);
+ if (v.IsGhost) {
// only emit non-ghosts (we get here only for local variables introduced implicitly by call statements)
return;
}
- Indent(indent);
- wr.Write("{0} @{1}", TypeName(s.Type), s.CompileName);
+ Indent(indent, wr);
+ wr.Write("{0} @{1}", TypeName(v.Type, wr), v.CompileName);
if (alwaysInitialize) {
// produce a default value
- wr.WriteLine(" = {0};", DefaultValue(s.Type));
+ wr.WriteLine(" = {0};", DefaultValue(v.Type, wr));
} else {
wr.WriteLine(";");
}
}
- void MatchCasePrelude(string source, UserDefinedType sourceType, DatatypeCtor ctor, List<BoundVar/*!*/>/*!*/ arguments, int caseIndex, int caseCount, int indent) {
+ void MatchCasePrelude(string source, UserDefinedType sourceType, DatatypeCtor ctor, List<BoundVar/*!*/>/*!*/ arguments, int caseIndex, int caseCount, int indent, TextWriter wr) {
Contract.Requires(source != null);
Contract.Requires(sourceType != null);
Contract.Requires(ctor != null);
@@ -1994,7 +2276,7 @@ namespace Microsoft.Dafny {
// if (source.is_Ctor0) {
// FormalType f0 = ((Dt_Ctor0)source._D).a0;
// ...
- Indent(indent);
+ Indent(indent, wr);
wr.Write("{0}if (", caseIndex == 0 ? "" : "} else ");
if (caseIndex == caseCount - 1) {
wr.Write("true");
@@ -2009,9 +2291,9 @@ namespace Microsoft.Dafny {
if (!arg.IsGhost) {
BoundVar bv = arguments[m];
// FormalType f0 = ((Dt_Ctor0)source._D).a0;
- Indent(indent + IndentAmount);
+ Indent(indent + IndentAmount, wr);
wr.WriteLine("{0} @{1} = (({2}){3}._D).@{4};",
- TypeName(bv.Type), bv.CompileName, DtCtorName(ctor, sourceType.TypeArgs), source, FormalName(arg, k));
+ TypeName(bv.Type, wr), bv.CompileName, DtCtorName(ctor, sourceType.TypeArgs, wr), source, FormalName(arg, k));
k++;
}
}
@@ -2022,51 +2304,51 @@ namespace Microsoft.Dafny {
/// <summary>
/// Before calling TrParenExpr(expr), the caller must have spilled the let variables declared in "expr".
/// </summary>
- void TrParenExpr(string prefix, Expression expr) {
+ void TrParenExpr(string prefix, Expression expr, TextWriter wr, bool inLetExprBody) {
Contract.Requires(prefix != null);
Contract.Requires(expr != null);
wr.Write(prefix);
- TrParenExpr(expr);
+ TrParenExpr(expr, wr, inLetExprBody);
}
/// <summary>
/// Before calling TrParenExpr(expr), the caller must have spilled the let variables declared in "expr".
/// </summary>
- void TrParenExpr(Expression expr) {
+ void TrParenExpr(Expression expr, TextWriter wr, bool inLetExprBody) {
Contract.Requires(expr != null);
wr.Write("(");
- TrExpr(expr);
+ TrExpr(expr, wr, inLetExprBody);
wr.Write(")");
}
/// <summary>
/// Before calling TrExprList(exprs), the caller must have spilled the let variables declared in expressions in "exprs".
/// </summary>
- void TrExprList(List<Expression/*!*/>/*!*/ exprs) {
+ void TrExprList(List<Expression/*!*/>/*!*/ exprs, TextWriter wr, bool inLetExprBody) {
Contract.Requires(cce.NonNullElements(exprs));
wr.Write("(");
string sep = "";
foreach (Expression e in exprs) {
wr.Write(sep);
- TrExpr(e);
+ TrExpr(e, wr, inLetExprBody);
sep = ", ";
}
wr.Write(")");
}
- void TrExprPairList(List<ExpressionPair/*!*/>/*!*/ exprs) {
+ void TrExprPairList(List<ExpressionPair/*!*/>/*!*/ exprs, TextWriter wr, bool inLetExprBody) {
Contract.Requires(cce.NonNullElements(exprs));
wr.Write("(");
string sep = "";
foreach (ExpressionPair p in exprs) {
wr.Write(sep);
wr.Write("new Dafny.Pair<");
- wr.Write(TypeName(p.A.Type));
+ wr.Write(TypeName(p.A.Type, wr));
wr.Write(",");
- wr.Write(TypeName(p.B.Type));
+ wr.Write(TypeName(p.B.Type, wr));
wr.Write(">(");
- TrExpr(p.A);
+ TrExpr(p.A, wr, inLetExprBody);
wr.Write(",");
- TrExpr(p.B);
+ TrExpr(p.B, wr, inLetExprBody);
wr.Write(")");
sep = ", ";
}
@@ -2076,13 +2358,15 @@ namespace Microsoft.Dafny {
/// <summary>
/// Before calling TrExpr(expr), the caller must have spilled the let variables declared in "expr".
/// </summary>
- void TrExpr(Expression expr)
+ void TrExpr(Expression expr, TextWriter wr, bool inLetExprBody)
{
Contract.Requires(expr != null);
if (expr is LiteralExpr) {
LiteralExpr e = (LiteralExpr)expr;
- if (e.Value == null) {
- wr.Write("({0})null", TypeName(e.Type));
+ if (e is StaticReceiverExpr) {
+ wr.Write(TypeName(e.Type, wr));
+ } else if (e.Value == null) {
+ wr.Write("({0})null", TypeName(e.Type, wr));
} else if (e.Value is bool) {
wr.Write((bool)e.Value ? "true" : "false");
} else if (e is CharLiteralExpr) {
@@ -2123,41 +2407,49 @@ namespace Microsoft.Dafny {
} else if (expr is IdentifierExpr) {
var e = (IdentifierExpr)expr;
- wr.Write("@" + e.Var.CompileName);
-
+ if (e.Var is Formal && inLetExprBody && !((Formal)e.Var).InParam) {
+ // out param in letExpr body, need to copy it to a temp since
+ // letExpr body is translated to an anonymous function that doesn't
+ // allow out parameters
+ var name = string.Format("_pat_let_tv{0}", GetUniqueAstNumber(e));
+ wr.Write("@" + name);
+ copyInstrWriter.Append("var @" + name + "= @" + e.Var.CompileName + ";\n");
+ } else {
+ wr.Write("@" + e.Var.CompileName);
+ }
} else if (expr is SetDisplayExpr) {
var e = (SetDisplayExpr)expr;
var elType = e.Type.AsSetType.Arg;
- wr.Write("{0}<{1}>.FromElements", DafnySetClass, TypeName(elType));
- TrExprList(e.Elements);
+ wr.Write("{0}<{1}>.FromElements", DafnySetClass, TypeName(elType, wr));
+ TrExprList(e.Elements, wr, inLetExprBody);
} else if (expr is MultiSetDisplayExpr) {
var e = (MultiSetDisplayExpr)expr;
var elType = e.Type.AsMultiSetType.Arg;
- wr.Write("{0}<{1}>.FromElements", DafnyMultiSetClass, TypeName(elType));
- TrExprList(e.Elements);
+ wr.Write("{0}<{1}>.FromElements", DafnyMultiSetClass, TypeName(elType, wr));
+ TrExprList(e.Elements, wr, inLetExprBody);
} else if (expr is SeqDisplayExpr) {
var e = (SeqDisplayExpr)expr;
var elType = e.Type.AsSeqType.Arg;
- wr.Write("{0}<{1}>.FromElements", DafnySeqClass, TypeName(elType));
- TrExprList(e.Elements);
+ wr.Write("{0}<{1}>.FromElements", DafnySeqClass, TypeName(elType, wr));
+ TrExprList(e.Elements, wr, inLetExprBody);
} else if (expr is MapDisplayExpr) {
MapDisplayExpr e = (MapDisplayExpr)expr;
- wr.Write("{0}.FromElements", TypeName(e.Type));
- TrExprPairList(e.Elements);
+ wr.Write("{0}.FromElements", TypeName(e.Type, wr));
+ TrExprPairList(e.Elements, wr, inLetExprBody);
} else if (expr is MemberSelectExpr) {
MemberSelectExpr e = (MemberSelectExpr)expr;
SpecialField sf = e.Member as SpecialField;
if (sf != null) {
wr.Write(sf.PreString);
- TrParenExpr(e.Obj);
+ TrParenExpr(e.Obj, wr, inLetExprBody);
wr.Write(".@{0}", sf.CompiledName);
wr.Write(sf.PostString);
} else {
- TrParenExpr(e.Obj);
+ TrExpr(e.Obj, wr, inLetExprBody);
wr.Write(".@{0}", e.Member.CompileName);
}
@@ -2167,50 +2459,50 @@ namespace Microsoft.Dafny {
if (e.Seq.Type.IsArrayType) {
if (e.SelectOne) {
Contract.Assert(e.E0 != null && e.E1 == null);
- TrParenExpr(e.Seq);
+ TrParenExpr(e.Seq, wr, inLetExprBody);
wr.Write("[(int)");
- TrParenExpr(e.E0);
+ TrParenExpr(e.E0, wr, inLetExprBody);
wr.Write("]");
} else {
- TrParenExpr("Dafny.Helpers.SeqFromArray", e.Seq);
+ TrParenExpr("Dafny.Helpers.SeqFromArray", e.Seq, wr, inLetExprBody);
if (e.E1 != null) {
- TrParenExpr(".Take", e.E1);
+ TrParenExpr(".Take", e.E1, wr, inLetExprBody);
}
if (e.E0 != null) {
- TrParenExpr(".Drop", e.E0);
+ TrParenExpr(".Drop", e.E0, wr, inLetExprBody);
}
}
} else if (e.SelectOne) {
Contract.Assert(e.E0 != null && e.E1 == null);
- TrParenExpr(e.Seq);
- TrParenExpr(".Select", e.E0);
+ TrParenExpr(e.Seq, wr, inLetExprBody);
+ TrParenExpr(".Select", e.E0, wr, inLetExprBody);
} else {
- TrParenExpr(e.Seq);
+ TrParenExpr(e.Seq, wr, inLetExprBody);
if (e.E1 != null) {
- TrParenExpr(".Take", e.E1);
+ TrParenExpr(".Take", e.E1, wr, inLetExprBody);
}
if (e.E0 != null) {
- TrParenExpr(".Drop", e.E0);
+ TrParenExpr(".Drop", e.E0, wr, inLetExprBody);
}
}
} else if (expr is MultiSetFormingExpr) {
var e = (MultiSetFormingExpr)expr;
- wr.Write("{0}<{1}>", DafnyMultiSetClass, TypeName(e.E.Type.AsCollectionType.Arg));
+ wr.Write("{0}<{1}>", DafnyMultiSetClass, TypeName(e.E.Type.AsCollectionType.Arg, wr));
var eeType = e.E.Type.NormalizeExpand();
if (eeType is SeqType) {
- TrParenExpr(".FromSeq", e.E);
+ TrParenExpr(".FromSeq", e.E, wr, inLetExprBody);
} else if (eeType is SetType) {
- TrParenExpr(".FromSet", e.E);
+ TrParenExpr(".FromSet", e.E, wr, inLetExprBody);
} else {
Contract.Assert(false); throw new cce.UnreachableException();
}
} else if (expr is MultiSelectExpr) {
MultiSelectExpr e = (MultiSelectExpr)expr;
- TrParenExpr(e.Array);
+ TrParenExpr(e.Array, wr, inLetExprBody);
string prefix = "[";
foreach (Expression idx in e.Indices) {
wr.Write("{0}(int)", prefix);
- TrParenExpr(idx);
+ TrParenExpr(idx, wr, inLetExprBody);
prefix = ", ";
}
wr.Write("]");
@@ -2219,47 +2511,46 @@ namespace Microsoft.Dafny {
SeqUpdateExpr e = (SeqUpdateExpr)expr;
if (e.ResolvedUpdateExpr != null)
{
- TrExpr(e.ResolvedUpdateExpr);
+ TrExpr(e.ResolvedUpdateExpr, wr, inLetExprBody);
}
else
{
- TrParenExpr(e.Seq);
+ TrParenExpr(e.Seq, wr, inLetExprBody);
wr.Write(".Update(");
- TrExpr(e.Index);
+ TrExpr(e.Index, wr, inLetExprBody);
wr.Write(", ");
- TrExpr(e.Value);
+ TrExpr(e.Value, wr, inLetExprBody);
wr.Write(")");
}
} else if (expr is FunctionCallExpr) {
FunctionCallExpr e = (FunctionCallExpr)expr;
- CompileFunctionCallExpr(e, wr, TrExpr);
+ CompileFunctionCallExpr(e, wr, wr, inLetExprBody, TrExpr);
} else if (expr is ApplyExpr) {
var e = expr as ApplyExpr;
wr.Write("Dafny.Helpers.Id<");
- wr.Write(TypeName(e.Function.Type));
+ wr.Write(TypeName(e.Function.Type, wr));
wr.Write(">(");
- TrExpr(e.Function);
+ TrExpr(e.Function, wr, inLetExprBody);
wr.Write(")");
- TrExprList(e.Args);
+ TrExprList(e.Args, wr, inLetExprBody);
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
Contract.Assert(dtv.Ctor != null); // since dtv has been successfully resolved
- var typeParams = dtv.InferredTypeArgs.Count == 0 ? "" : string.Format("<{0}>", TypeNames(dtv.InferredTypeArgs));
-
- wr.Write("new {0}{1}(", DtName(dtv.Ctor.EnclosingDatatype), typeParams);
+ var typeParams = dtv.InferredTypeArgs.Count == 0 ? "" : string.Format("<{0}>", TypeNames(dtv.InferredTypeArgs, wr));
+ wr.Write("new @{0}{1}(", DtName(dtv.Ctor.EnclosingDatatype), typeParams);
if (!dtv.IsCoCall) {
// For an ordinary constructor (that is, one that does not guard any co-recursive calls), generate:
// new Dt_Cons<T>( args )
- wr.Write("new {0}(", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs));
+ wr.Write("new {0}(", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs, wr));
string sep = "";
for (int i = 0; i < dtv.Arguments.Count; i++) {
Formal formal = dtv.Ctor.Formals[i];
if (!formal.IsGhost) {
wr.Write(sep);
- TrExpr(dtv.Arguments[i]);
+ TrExpr(dtv.Arguments[i], wr, inLetExprBody);
sep = ", ";
}
}
@@ -2288,17 +2579,17 @@ namespace Microsoft.Dafny {
arg = varName;
wr.Write("var {0} = ", varName);
- TrExpr(actual);
+ TrExpr(actual, wr, inLetExprBody);
wr.Write("; ");
} else {
var sw = new StringWriter();
- CompileFunctionCallExpr(fce, sw, (exp) => {
+ CompileFunctionCallExpr(fce, sw, wr, inLetExprBody, (exp, wrr, inLetExpr) => {
string varName = idGenerator.FreshId("_ac");
sw.Write(varName);
- wr.Write("var {0} = ", varName);
- TrExpr(exp);
- wr.Write("; ");
+ wrr.Write("var {0} = ", varName);
+ TrExpr(exp, wrr, inLetExpr);
+ wrr.Write("; ");
});
arg = sw.ToString();
@@ -2310,7 +2601,7 @@ namespace Microsoft.Dafny {
wr.Write("return () => { return ");
- wr.Write("new {0}({1}", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs), args);
+ wr.Write("new {0}({1}", DtCtorName(dtv.Ctor, dtv.InferredTypeArgs, wr), args);
wr.Write("); }; })())");
}
wr.Write(")");
@@ -2323,11 +2614,11 @@ namespace Microsoft.Dafny {
switch (e.Op) {
case UnaryOpExpr.Opcode.Not:
wr.Write("!");
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
break;
case UnaryOpExpr.Opcode.Cardinality:
wr.Write("new BigInteger(");
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
wr.Write(".Length)");
break;
default:
@@ -2345,7 +2636,7 @@ namespace Microsoft.Dafny {
if (AsNativeType(e.E.Type) != null) {
wr.Write("new BigInteger");
}
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
};
Action toIntCast = () => {
Contract.Assert(toInt);
@@ -2361,7 +2652,7 @@ namespace Microsoft.Dafny {
} else if (!fromInt && toInt) {
// real -> int
toIntCast();
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
wr.Write(".ToBigInteger()");
} else if (AsNativeType(e.ToType) != null) {
toIntCast();
@@ -2373,14 +2664,14 @@ namespace Microsoft.Dafny {
wr.Write("(" + (BigInteger)lit.Value + AsNativeType(e.ToType).Suffix + ")");
} else if ((u != null && u.Op == UnaryOpExpr.Opcode.Cardinality) || (m != null && m.MemberName == "Length" && m.Obj.Type.IsArrayType)) {
// Optimize .Length to avoid intermediate BigInteger
- TrParenExpr((u != null) ? u.E : m.Obj);
+ TrParenExpr((u != null) ? u.E : m.Obj, wr, inLetExprBody);
if (AsNativeType(e.ToType).UpperBound <= new BigInteger(0x80000000U)) {
wr.Write(".Length");
} else {
wr.Write(".LongLength");
}
} else {
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
}
} else if (e.ToType.IsIntegerType && AsNativeType(e.E.Type) != null) {
fromIntAsBigInteger();
@@ -2388,7 +2679,7 @@ namespace Microsoft.Dafny {
Contract.Assert(fromInt == toInt);
Contract.Assert(AsNativeType(e.ToType) == null);
Contract.Assert(AsNativeType(e.E.Type) == null);
- TrParenExpr(e.E);
+ TrParenExpr(e.E, wr, inLetExprBody);
}
} else if (expr is BinaryExpr) {
@@ -2408,27 +2699,27 @@ namespace Microsoft.Dafny {
opString = "&&"; break;
case BinaryExpr.ResolvedOpcode.EqCommon: {
- if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) {
- callString = "Equals";
- } else if (e.E0.Type.IsRefType) {
+ if (e.E0.Type.IsRefType) {
// Dafny's type rules are slightly different C#, so we may need a cast here.
// For example, Dafny allows x==y if x:array<T> and y:array<int> and T is some
// type parameter.
opString = "== (object)";
+ } else if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) {
+ callString = "Equals";
} else {
opString = "==";
}
break;
}
case BinaryExpr.ResolvedOpcode.NeqCommon: {
- if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) {
- preOpString = "!";
- callString = "Equals";
- } else if (e.E0.Type.IsRefType) {
+ if (e.E0.Type.IsRefType) {
// Dafny's type rules are slightly different C#, so we may need a cast here.
// For example, Dafny allows x==y if x:array<T> and y:array<int> and T is some
// type parameter.
opString = "!= (object)";
+ } else if (e.E0.Type.IsDatatype || e.E0.Type.IsTypeParameter || e.E0.Type.SupportsEquality) {
+ preOpString = "!";
+ callString = "Equals";
} else {
opString = "!=";
}
@@ -2457,9 +2748,9 @@ namespace Microsoft.Dafny {
if (expr.Type.IsIntegerType || (AsNativeType(expr.Type) != null && AsNativeType(expr.Type).LowerBound < BigInteger.Zero)) {
string suffix = AsNativeType(expr.Type) != null ? ("_" + AsNativeType(expr.Type).Name) : "";
wr.Write("Dafny.Helpers.EuclideanDivision" + suffix + "(");
- TrParenExpr(e.E0);
+ TrParenExpr(e.E0, wr, inLetExprBody);
wr.Write(", ");
- TrExpr(e.E1);
+ TrExpr(e.E1, wr, inLetExprBody);
wr.Write(")");
} else {
opString = "/"; // for reals
@@ -2469,9 +2760,9 @@ namespace Microsoft.Dafny {
if (expr.Type.IsIntegerType || (AsNativeType(expr.Type) != null && AsNativeType(expr.Type).LowerBound < BigInteger.Zero)) {
string suffix = AsNativeType(expr.Type) != null ? ("_" + AsNativeType(expr.Type).Name) : "";
wr.Write("Dafny.Helpers.EuclideanModulus" + suffix + "(");
- TrParenExpr(e.E0);
+ TrParenExpr(e.E0, wr, inLetExprBody);
wr.Write(", ");
- TrExpr(e.E1);
+ TrExpr(e.E1, wr, inLetExprBody);
wr.Write(")");
} else {
opString = "%"; // for reals
@@ -2506,18 +2797,18 @@ namespace Microsoft.Dafny {
case BinaryExpr.ResolvedOpcode.InSet:
case BinaryExpr.ResolvedOpcode.InMultiSet:
case BinaryExpr.ResolvedOpcode.InMap:
- TrParenExpr(e.E1);
+ TrParenExpr(e.E1, wr, inLetExprBody);
wr.Write(".Contains(");
- TrExpr(e.E0);
+ TrExpr(e.E0, wr, inLetExprBody);
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.NotInSet:
case BinaryExpr.ResolvedOpcode.NotInMultiSet:
case BinaryExpr.ResolvedOpcode.NotInMap:
wr.Write("!");
- TrParenExpr(e.E1);
+ TrParenExpr(e.E1, wr, inLetExprBody);
wr.Write(".Contains(");
- TrExpr(e.E0);
+ TrExpr(e.E0, wr, inLetExprBody);
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.Union:
@@ -2537,16 +2828,16 @@ namespace Microsoft.Dafny {
case BinaryExpr.ResolvedOpcode.Concat:
callString = "Concat"; break;
case BinaryExpr.ResolvedOpcode.InSeq:
- TrParenExpr(e.E1);
+ TrParenExpr(e.E1, wr, inLetExprBody);
wr.Write(".Contains(");
- TrExpr(e.E0);
+ TrExpr(e.E0, wr, inLetExprBody);
wr.Write(")");
break;
case BinaryExpr.ResolvedOpcode.NotInSeq:
wr.Write("!");
- TrParenExpr(e.E1);
+ TrParenExpr(e.E1, wr, inLetExprBody);
wr.Write(".Contains(");
- TrExpr(e.E0);
+ TrExpr(e.E0, wr, inLetExprBody);
wr.Write(")");
break;
@@ -2560,17 +2851,17 @@ namespace Microsoft.Dafny {
wr.Write("(" + nativeType.Name + ")(");
}
wr.Write(preOpString);
- TrParenExpr(e.E0);
+ TrParenExpr(e.E0, wr, inLetExprBody);
wr.Write(" {0} ", opString);
- TrParenExpr(e.E1);
+ TrParenExpr(e.E1, wr, inLetExprBody);
if (needsCast) {
wr.Write(")");
}
} else if (callString != null) {
wr.Write(preOpString);
- TrParenExpr(e.E0);
+ TrParenExpr(e.E0, wr, inLetExprBody);
wr.Write(".@{0}(", callString);
- TrExpr(e.E1);
+ TrExpr(e.E1, wr, inLetExprBody);
wr.Write(")");
}
@@ -2593,17 +2884,18 @@ namespace Microsoft.Dafny {
if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) {
var rhsName = string.Format("_pat_let{0}_{1}", GetUniqueAstNumber(e), i);
wr.Write("Dafny.Helpers.Let<");
- wr.Write(TypeName(e.RHSs[i].Type) + "," + TypeName(e.Body.Type));
+ wr.Write(TypeName(e.RHSs[i].Type, wr) + "," + TypeName(e.Body.Type, wr));
wr.Write(">(");
- TrExpr(e.RHSs[i]);
+ TrExpr(e.RHSs[i], wr, inLetExprBody);
wr.Write(", " + rhsName + " => ");
neededCloseParens++;
- var c = TrCasePattern(lhs, rhsName, e.Body.Type);
+ var c = TrCasePattern(lhs, rhsName, e.Body.Type, wr);
Contract.Assert(c != 0); // we already checked that there's at least one non-ghost
neededCloseParens += c;
}
}
- TrExpr(e.Body);
+
+ TrExpr(e.Body, wr, true);
for (int i = 0; i < neededCloseParens; i++) {
wr.Write(")");
}
@@ -2612,7 +2904,7 @@ namespace Microsoft.Dafny {
// ghost var x,y :| Constraint; E
// is compiled just like E is, because the resolver has already checked that x,y (or other ghost variables, for that matter) don't
// occur in E (moreover, the verifier has checked that values for x,y satisfying Constraint exist).
- TrExpr(e.Body);
+ TrExpr(e.Body, wr, inLetExprBody);
} else {
// The Dafny "let" expression
// var x,y :| Constraint; E
@@ -2627,17 +2919,17 @@ namespace Microsoft.Dafny {
Contract.Assert(e.RHSs.Count == 1); // checked by resolution
if (e.Constraint_MissingBounds != null) {
foreach (var bv in e.Constraint_MissingBounds) {
- Error("this let-such-that expression is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", bv.Name, e.tok.line);
+ Error("this let-such-that expression is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}' (line {1})", wr, bv.Name, e.tok.line);
}
} else {
- wr.Write("Dafny.Helpers.Let<int," + TypeName(e.Body.Type) + ">(0, _let_dummy_" + GetUniqueAstNumber(e) + " => {");
+ wr.Write("Dafny.Helpers.Let<int," + TypeName(e.Body.Type, wr) + ">(0, _let_dummy_" + GetUniqueAstNumber(e) + " => {");
foreach (var bv in e.BoundVars) {
- wr.Write("{0} @{1}", TypeName(bv.Type), bv.CompileName);
- wr.WriteLine(" = {0};", DefaultValue(bv.Type));
+ wr.Write("{0} @{1}", TypeName(bv.Type, wr), bv.CompileName);
+ wr.WriteLine(" = {0};", DefaultValue(bv.Type, wr));
}
- TrAssignSuchThat(0, new List<IVariable>(e.BoundVars).ConvertAll(bv => (IVariable)bv), e.RHSs[0], e.Constraint_Bounds, e.tok.line);
+ TrAssignSuchThat(0, new List<IVariable>(e.BoundVars).ConvertAll(bv => (IVariable)bv), e.RHSs[0], e.Constraint_Bounds, e.tok.line, wr, inLetExprBody);
wr.Write(" return ");
- TrExpr(e.Body);
+ TrExpr(e.Body, wr, true);
wr.Write("; })");
}
}
@@ -2657,7 +2949,7 @@ namespace Microsoft.Dafny {
// }(src)
string source = idGenerator.FreshId("_source");
- wr.Write("new Dafny.Helpers.Function<{0}, {1}>(delegate ({0} {2}) {{ ", TypeName(e.Source.Type), TypeName(e.Type), source);
+ wr.Write("new Dafny.Helpers.Function<{0}, {1}>(delegate ({0} {2}) {{ ", TypeName(e.Source.Type, wr), TypeName(e.Type, wr), source);
if (e.Cases.Count == 0) {
// the verifier would have proved we never get here; still, we need some code that will compile
@@ -2666,9 +2958,9 @@ namespace Microsoft.Dafny {
int i = 0;
var sourceType = (UserDefinedType)e.Source.Type.NormalizeExpand();
foreach (MatchCaseExpr mc in e.Cases) {
- MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, e.Cases.Count, 0);
+ MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, e.Cases.Count, 0, wr);
wr.Write("return ");
- TrExpr(mc.Body);
+ TrExpr(mc.Body, wr, inLetExprBody);
wr.Write("; ");
i++;
}
@@ -2676,11 +2968,14 @@ namespace Microsoft.Dafny {
}
// We end with applying the source expression to the delegate we just built
wr.Write("})(");
- TrExpr(e.Source);
+ TrExpr(e.Source, wr, inLetExprBody);
wr.Write(")");
} else if (expr is QuantifierExpr) {
var e = (QuantifierExpr)expr;
+
+ // Compilation does not check whether a quantifier was split.
+
Contract.Assert(e.Bounds != null); // for non-ghost quantifiers, the resolver would have insisted on finding bounds
var n = e.BoundVars.Count;
Contract.Assert(e.Bounds.Count == n);
@@ -2690,27 +2985,29 @@ namespace Microsoft.Dafny {
// emit: Dafny.Helpers.QuantX(boundsInformation, isForall, bv => body)
if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("Dafny.Helpers.QuantBool(");
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ wr.Write("Dafny.Helpers.QuantChar(");
} else if (bound is ComprehensionExpr.IntBoundedPool) {
var b = (ComprehensionExpr.IntBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantInt(");
- TrExpr(b.LowerBound);
+ TrExpr(b.LowerBound, wr, inLetExprBody);
wr.Write(", ");
- TrExpr(b.UpperBound);
+ TrExpr(b.UpperBound, wr, inLetExprBody);
wr.Write(", ");
} else if (bound is ComprehensionExpr.SetBoundedPool) {
var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantSet(");
- TrExpr(b.Set);
+ TrExpr(b.Set, wr, inLetExprBody);
wr.Write(", ");
} else if (bound is ComprehensionExpr.MapBoundedPool) {
var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantMap(");
- TrExpr(b.Map);
+ TrExpr(b.Map, wr, inLetExprBody);
wr.Write(", ");
} else if (bound is ComprehensionExpr.SeqBoundedPool) {
var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantSeq(");
- TrExpr(b.Seq);
+ TrExpr(b.Seq, wr, inLetExprBody);
wr.Write(", ");
} else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
@@ -2723,7 +3020,7 @@ namespace Microsoft.Dafny {
wr.Write("{0}, ", expr is ForallExpr ? "true" : "false");
wr.Write("@{0} => ", bv.CompileName);
}
- TrExpr(e.LogicalBody());
+ TrExpr(e.LogicalBody(true), wr, inLetExprBody);
for (int i = 0; i < n; i++) {
wr.Write(")");
}
@@ -2747,9 +3044,10 @@ namespace Microsoft.Dafny {
// return Dafny.Set<G>.FromCollection(_coll);
// })()
Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds
- var typeName = TypeName(e.Type.AsSetType.Arg);
+ var typeName = TypeName(e.Type.AsSetType.Arg, wr);
+ var collection_name = idGenerator.FreshId("_coll");
wr.Write("((Dafny.Helpers.ComprehensionDelegate<{0}>)delegate() {{ ", typeName);
- wr.Write("var _coll = new System.Collections.Generic.List<{0}>(); ", typeName);
+ wr.Write("var {0} = new System.Collections.Generic.List<{1}>(); ", collection_name, typeName);
var n = e.BoundVars.Count;
Contract.Assert(e.Bounds.Count == n);
for (int i = 0; i < n; i++) {
@@ -2757,44 +3055,51 @@ namespace Microsoft.Dafny {
var bv = e.BoundVars[i];
if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName);
} else if (bound is ComprehensionExpr.IntBoundedPool) {
var b = (ComprehensionExpr.IntBoundedPool)bound;
- wr.Write("for (var @{0} = ", bv.CompileName);
- TrExpr(b.LowerBound);
- wr.Write("; @{0} < ", bv.CompileName);
- TrExpr(b.UpperBound);
- wr.Write("; @{0}++) {{ ", bv.CompileName);
+ if (AsNativeType(bv.Type) != null) {
+ wr.Write("foreach (var @{0} in @{1}.IntegerRange(", bv.CompileName, bv.Type.AsNewtype.FullCompileName);
+ } else {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", bv.CompileName);
+ }
+ TrExpr(b.LowerBound, wr, inLetExprBody);
+ wr.Write(", ");
+ TrExpr(b.UpperBound, wr, inLetExprBody);
+ wr.Write(")) { ");
} else if (bound is ComprehensionExpr.SetBoundedPool) {
var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Set);
+ TrExpr(b.Set, wr, inLetExprBody);
wr.Write(").Elements) { ");
} else if (bound is ComprehensionExpr.MapBoundedPool) {
var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Map);
+ TrExpr(b.Map, wr, inLetExprBody);
wr.Write(").Domain) { ");
} else if (bound is ComprehensionExpr.SeqBoundedPool) {
var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Seq);
+ TrExpr(b.Seq, wr, inLetExprBody);
wr.Write(").Elements) { ");
} else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
- wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type));
+ wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type, wr));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
}
}
wr.Write("if (");
- TrExpr(e.Range);
- wr.Write(") { _coll.Add(");
- TrExpr(e.Term);
+ TrExpr(e.Range, wr, inLetExprBody);
+ wr.Write(") {");
+ wr.Write("{0}.Add(", collection_name);
+ TrExpr(e.Term, wr, inLetExprBody);
wr.Write("); }");
for (int i = 0; i < n; i++) {
wr.Write("}");
}
- wr.Write("return Dafny.Set<{0}>.FromCollection(_coll); ", typeName);
+ wr.Write("return Dafny.Set<{0}>.FromCollection({1}); ", typeName, collection_name);
wr.Write("})()");
} else if (expr is MapComprehension) {
@@ -2816,58 +3121,63 @@ namespace Microsoft.Dafny {
// return Dafny.Map<U, V>.FromElements(_coll);
// })()
Contract.Assert(e.Bounds != null); // the resolver would have insisted on finding bounds
- var domtypeName = TypeName(e.Type.AsMapType.Domain);
- var rantypeName = TypeName(e.Type.AsMapType.Range);
+ var domtypeName = TypeName(e.Type.AsMapType.Domain, wr);
+ var rantypeName = TypeName(e.Type.AsMapType.Range, wr);
+ var collection_name = idGenerator.FreshId("_coll");
wr.Write("((Dafny.Helpers.MapComprehensionDelegate<{0},{1}>)delegate() {{ ", domtypeName, rantypeName);
- wr.Write("var _coll = new System.Collections.Generic.List<Dafny.Pair<{0},{1}>>(); ", domtypeName, rantypeName);
+ wr.Write("var {0} = new System.Collections.Generic.List<Dafny.Pair<{1},{2}>>(); ", collection_name, domtypeName, rantypeName);
var n = e.BoundVars.Count;
Contract.Assert(e.Bounds.Count == n && n == 1);
var bound = e.Bounds[0];
var bv = e.BoundVars[0];
if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName);
} else if (bound is ComprehensionExpr.IntBoundedPool) {
var b = (ComprehensionExpr.IntBoundedPool)bound;
- wr.Write("for (var @{0} = ", bv.CompileName);
- TrExpr(b.LowerBound);
- wr.Write("; @{0} < ", bv.CompileName);
- TrExpr(b.UpperBound);
- wr.Write("; @{0}++) {{ ", bv.CompileName);
+ if (AsNativeType(bv.Type) != null) {
+ wr.Write("foreach (var @{0} in @{1}.IntegerRange(", bv.CompileName, bv.Type.AsNewtype.FullCompileName);
+ } else {
+ wr.Write("foreach (var @{0} in Dafny.Helpers.IntegerRange(", bv.CompileName);
+ }
+ TrExpr(b.LowerBound, wr, inLetExprBody);
+ wr.Write(", ");
+ TrExpr(b.UpperBound, wr, inLetExprBody);
+ wr.Write(")) { ");
} else if (bound is ComprehensionExpr.SetBoundedPool) {
var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Set);
+ TrExpr(b.Set, wr, inLetExprBody);
wr.Write(").Elements) { ");
} else if (bound is ComprehensionExpr.MapBoundedPool) {
var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Map);
+ TrExpr(b.Map, wr, inLetExprBody);
wr.Write(").Domain) { ");
} else if (bound is ComprehensionExpr.SeqBoundedPool) {
var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
- TrExpr(b.Seq);
+ TrExpr(b.Seq, wr, inLetExprBody);
wr.Write(").Elements) { ");
} else {
+ // TODO: handle ComprehensionExpr.SubSetBoundedPool
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
}
wr.Write("if (");
- TrExpr(e.Range);
+ TrExpr(e.Range, wr, inLetExprBody);
wr.Write(") { ");
- wr.Write("_coll.Add(new Dafny.Pair<{0},{1}>(@{2},", domtypeName, rantypeName, bv.CompileName);
- TrExpr(e.Term);
+ wr.Write("{0}.Add(new Dafny.Pair<{1},{2}>(@{3},", collection_name, domtypeName, rantypeName, bv.CompileName);
+ TrExpr(e.Term, wr, inLetExprBody);
wr.Write(")); }");
wr.Write("}");
- wr.Write("return Dafny.Map<{0},{1}>.FromCollection(_coll); ", domtypeName, rantypeName);
+ wr.Write("return Dafny.Map<{0},{1}>.FromCollection({2}); ", domtypeName, rantypeName, collection_name);
wr.Write("})()");
} else if (expr is LambdaExpr) {
LambdaExpr e = (LambdaExpr)expr;
- ISet<IVariable> fvs = new HashSet<IVariable>();
- bool dontCare = false;
- Type dontCareT = null;
- Translator.ComputeFreeVariables(expr, fvs, ref dontCare, ref dontCare, ref dontCareT, false);
+ var fvs = Translator.ComputeFreeVariables(expr);
var sm = new Dictionary<IVariable, Expression>();
var bvars = new List<BoundVar>();
@@ -2887,46 +3197,46 @@ namespace Microsoft.Dafny {
var su = new Translator.Substituter(null, sm, new Dictionary<TypeParameter, Type>(), null);
- BetaRedex(bvars, fexprs, expr.Type, () => {
+ BetaRedex(bvars, fexprs, expr.Type, wr, inLetExprBody, () => {
wr.Write("(");
wr.Write(Util.Comma(e.BoundVars, bv => "@" + bv.CompileName));
wr.Write(") => ");
- TrExpr(su.Substitute(e.Body));
+ TrExpr(su.Substitute(e.Body), wr, inLetExprBody);
});
} else if (expr is StmtExpr) {
var e = (StmtExpr)expr;
- TrExpr(e.E);
+ TrExpr(e.E, wr, inLetExprBody);
} else if (expr is ITEExpr) {
ITEExpr e = (ITEExpr)expr;
wr.Write("(");
- TrExpr(e.Test);
+ TrExpr(e.Test, wr, inLetExprBody);
wr.Write(") ? (");
- TrExpr(e.Thn);
+ TrExpr(e.Thn, wr, inLetExprBody);
wr.Write(") : (");
- TrExpr(e.Els);
+ TrExpr(e.Els, wr, inLetExprBody);
wr.Write(")");
} else if (expr is ConcreteSyntaxExpression) {
var e = (ConcreteSyntaxExpression)expr;
- TrExpr(e.ResolvedExpression);
+ TrExpr(e.ResolvedExpression, wr, inLetExprBody);
} else if (expr is NamedExpr) {
- TrExpr(((NamedExpr)expr).Body);
+ TrExpr(((NamedExpr)expr).Body, wr, inLetExprBody);
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
}
}
- int TrCasePattern(CasePattern pat, string rhsString, Type bodyType) {
+ int TrCasePattern(CasePattern pat, string rhsString, Type bodyType, TextWriter wr) {
Contract.Requires(pat != null);
Contract.Requires(rhsString != null);
int c = 0;
if (pat.Var != null) {
var bv = pat.Var;
if (!bv.IsGhost) {
- wr.Write("Dafny.Helpers.Let<" + TypeName(bv.Type) + "," + TypeName(bodyType) + ">");
+ wr.Write("Dafny.Helpers.Let<" + TypeName(bv.Type, wr) + "," + TypeName(bodyType, wr) + ">");
wr.Write("(" + rhsString + ", @" + bv.CompileName + " => ");
c++;
}
@@ -2942,7 +3252,7 @@ namespace Microsoft.Dafny {
// nothing to compile, but do a sanity check
Contract.Assert(!Contract.Exists(arg.Vars, bv => !bv.IsGhost));
} else {
- c += TrCasePattern(arg, string.Format("(({0})({1})._D).@{2}", DtCtorName(ctor, ((DatatypeValue)pat.Expr).InferredTypeArgs), rhsString, FormalName(formal, k)), bodyType);
+ c += TrCasePattern(arg, string.Format("(({0})({1})._D).@{2}", DtCtorName(ctor, ((DatatypeValue)pat.Expr).InferredTypeArgs, wr), rhsString, FormalName(formal, k)), bodyType, wr);
k++;
}
}
@@ -2950,36 +3260,40 @@ namespace Microsoft.Dafny {
return c;
}
- delegate void FCE_Arg_Translator(Expression e);
+ delegate void FCE_Arg_Translator(Expression e, TextWriter wr, bool inLetExpr=false);
- void CompileFunctionCallExpr(FunctionCallExpr e, TextWriter twr, FCE_Arg_Translator tr) {
+ void CompileFunctionCallExpr(FunctionCallExpr e, TextWriter twr, TextWriter wr, bool inLetExprBody, FCE_Arg_Translator tr) {
Function f = cce.NonNull(e.Function);
if (f.IsStatic) {
- twr.Write(TypeName_Companion(e.Receiver.Type));
+ twr.Write(TypeName_Companion(e.Receiver.Type, wr));
} else {
twr.Write("(");
- tr(e.Receiver);
+ tr(e.Receiver, wr, inLetExprBody);
twr.Write(")");
}
twr.Write(".@{0}", f.CompileName);
+ if (f.TypeArgs.Count != 0) {
+ List<Type> typeArgs = f.TypeArgs.ConvertAll(ta => e.TypeArgumentSubstitutions[ta]);
+ twr.Write("<" + TypeNames(typeArgs, wr) + ">");
+ }
twr.Write("(");
string sep = "";
for (int i = 0; i < e.Args.Count; i++) {
if (!e.Function.Formals[i].IsGhost) {
twr.Write(sep);
- tr(e.Args[i]);
+ tr(e.Args[i], wr);
sep = ", ";
}
}
twr.Write(")");
}
- void BetaRedex(List<BoundVar> bvars, List<Expression> exprs, Type bodyType, Action makeBody) {
+ void BetaRedex(List<BoundVar> bvars, List<Expression> exprs, Type bodyType, TextWriter wr, bool inLetExprBody, Action makeBody) {
Contract.Requires(bvars != null);
Contract.Requires(exprs != null);
Contract.Requires(bvars.Count == exprs.Count);
wr.Write("Dafny.Helpers.Id<");
- wr.Write(TypeName_UDT(ArrowType.Arrow_FullCompileName, Util.Snoc(bvars.ConvertAll(bv => bv.Type), bodyType)));
+ wr.Write(TypeName_UDT(ArrowType.Arrow_FullCompileName, Util.Snoc(bvars.ConvertAll(bv => bv.Type), bodyType), wr));
wr.Write(">((");
wr.Write(Util.Comma(bvars, bv => "@" + bv.CompileName));
wr.Write(") => ");
@@ -2987,7 +3301,7 @@ namespace Microsoft.Dafny {
makeBody();
wr.Write(")");
- TrExprList(exprs);
+ TrExprList(exprs, wr, inLetExprBody);
}
}
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index c03f5ce0..af7082a4 100644
--- a/Source/Dafny/Dafny.atg
+++ b/Source/Dafny/Dafny.atg
@@ -16,17 +16,120 @@ COMPILER Dafny
/*--------------------------------------------------------------------------*/
readonly Expression/*!*/ dummyExpr;
readonly AssignmentRhs/*!*/ dummyRhs;
-readonly FrameExpression/*!*/ dummyFrameExpr;
+readonly FrameExpression/*!*/ dummyFrameExpr;
readonly Statement/*!*/ dummyStmt;
readonly ModuleDecl theModule;
readonly BuiltIns theBuiltIns;
readonly bool theVerifyThisFile;
int anonymousIds = 0;
-struct MemberModifiers {
+/// <summary>
+/// Holds the modifiers given for a declaration
+///
+/// Not all modifiers are applicable to all kinds of declarations.
+/// Errors are given when a modify does not apply.
+/// We also record the tokens for the specified modifiers so that
+/// they can be used in error messages.
+/// </summary>
+struct DeclModifierData {
+ public bool IsAbstract;
+ public IToken AbstractToken;
public bool IsGhost;
+ public IToken GhostToken;
public bool IsStatic;
+ public IToken StaticToken;
public bool IsProtected;
+ public IToken ProtectedToken;
+ public bool IsExtern;
+ public IToken ExternToken;
+ public StringLiteralExpr ExternName;
+
+}
+
+// Check that token has not been set, then set it.
+public void CheckAndSetToken(ref IToken token)
+{
+ if (token != null) {
+ SemErr(t, "Duplicate declaration modifier: " + t.val);
+ }
+ token = t;
+}
+
+/// <summary>
+// A flags type used to tell what declaration modifiers are allowed for a declaration.
+/// </summary>
+[Flags]
+enum AllowedDeclModifiers {
+ None = 0,
+ Abstract = 1,
+ Ghost = 2,
+
+ // Means ghost not allowed because already implicitly ghost.
+ AlreadyGhost = 4,
+ Static = 8,
+ Protected = 16,
+ Extern = 32
+};
+
+/// <summary>
+/// Check the declaration modifiers against those that are allowed.
+///
+/// The 'allowed' parameter specifies which declaratio modifiers are allowed.
+/// The 'declCaption' parameter should be a string describing the kind of declaration.
+/// It is used in error messages.
+/// Any declaration modifiers that are present but not allowed are cleared.
+///</summary>
+void CheckDeclModifiers(DeclModifierData dmod, string declCaption, AllowedDeclModifiers allowed)
+{
+ if (dmod.IsAbstract && ((allowed & AllowedDeclModifiers.Abstract) == 0)) {
+ SemErr(dmod.AbstractToken, declCaption + " cannot be declared 'abstract'.");
+ dmod.IsAbstract = false;
+ }
+ if (dmod.IsGhost) {
+ if ((allowed & AllowedDeclModifiers.AlreadyGhost) != 0) {
+ SemErr(dmod.GhostToken, declCaption + " cannot be declared ghost (they are 'ghost' by default).");
+ dmod.IsGhost = false;
+ } else if ((allowed & AllowedDeclModifiers.Ghost) == 0) {
+ SemErr(dmod.GhostToken, declCaption + " cannot be declared 'ghost'.");
+ dmod.IsGhost = false;
+ }
+ }
+ if (dmod.IsStatic && ((allowed & AllowedDeclModifiers.Static) == 0)) {
+ SemErr(dmod.StaticToken, declCaption + " cannot be declared 'static'.");
+ dmod.IsStatic = false;
+ }
+ if (dmod.IsProtected && ((allowed & AllowedDeclModifiers.Protected) == 0)) {
+ SemErr(dmod.ProtectedToken, declCaption + " cannot be declared 'protected'.");
+ dmod.IsProtected = false;
+ }
+ if (dmod.IsExtern && ((allowed & AllowedDeclModifiers.Extern) == 0)) {
+ SemErr(dmod.ExternToken, declCaption + " cannot be declared 'extern'.");
+ dmod.IsExtern = false;
+ }
+}
+
+/// <summary>
+/// Encode an 'extern' declaration modifier as an {:extern name} attribute.
+///
+/// We also include an {:axiom} attribute since the specification of an
+/// external entity is assumed to hold, but only for methods or functions.
+///</summary>
+static void EncodeExternAsAttribute(DeclModifierData dmod, ref Attributes attrs, IToken/*!*/ id, bool needAxiom) {
+ if (dmod.IsExtern) {
+ StringLiteralExpr name = dmod.ExternName;
+ if (name == null) {
+ bool isVerbatimString = false;
+ name = new StringLiteralExpr(id, id.val, isVerbatimString);
+ }
+ var args = new List<Expression>();
+ args.Add(name);
+ attrs = new Attributes("extern", args, attrs);
+
+ // Also 'extern' implies 'axiom' for methods or functions.
+ if (needAxiom) {
+ attrs = new Attributes("axiom", new List<Expression>(), attrs);
+ }
+ }
}
///<summary>
@@ -41,11 +144,11 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built
string s;
if (filename == "stdin.dfy") {
s = Microsoft.Boogie.ParserHelper.Fill(System.Console.In, new List<string>());
- return Parse(s, filename, module, builtIns, errors, verifyThisFile);
+ return Parse(s, filename, filename, module, builtIns, errors, verifyThisFile);
} else {
using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) {
s = Microsoft.Boogie.ParserHelper.Fill(reader, new List<string>());
- return Parse(s, DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, module, builtIns, errors, verifyThisFile);
+ return Parse(s, filename, DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, module, builtIns, errors, verifyThisFile);
}
}
}
@@ -55,12 +158,12 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built
/// Returns the number of parsing errors encountered.
/// Note: first initialize the Scanner.
///</summary>
-public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) {
+public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) {
Contract.Requires(s != null);
Contract.Requires(filename != null);
Contract.Requires(module != null);
- Errors errors = new Errors();
- return Parse(s, filename, module, builtIns, errors, verifyThisFile);
+ Errors errors = new Errors(reporter);
+ return Parse(s, fullFilename, filename, module, builtIns, errors, verifyThisFile);
}
///<summary>
/// Parses top-level things (modules, classes, datatypes, class members)
@@ -68,18 +171,18 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module,
/// Returns the number of parsing errors encountered.
/// Note: first initialize the Scanner with the given Errors sink.
///</summary>
-public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns,
- Errors/*!*/ errors, bool verifyThisFile=true) {
+public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module,
+ BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {
Contract.Requires(s != null);
Contract.Requires(filename != null);
Contract.Requires(module != null);
Contract.Requires(errors != null);
byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
- Scanner scanner = new Scanner(ms, errors, filename);
+ Scanner scanner = new Scanner(ms, errors, fullFilename, filename);
Parser parser = new Parser(scanner, errors, module, builtIns, verifyThisFile);
parser.Parse();
- return parser.errors.count;
+ return parser.errors.ErrorCount;
}
public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true)
: this(scanner, errors) // the real work
@@ -104,6 +207,25 @@ bool IsAlternative() {
return la.kind == _lbrace && x.kind == _case;
}
+// an existential guard starts with an identifier and is then followed by
+// * a colon (if the first identifier is given an explicit type),
+// * a comma (if there's a list a bound variables and the first one is not given an explicit type),
+// * a start-attribute (if there's one bound variable and it is not given an explicit type and there are attributes), or
+// * a bored smiley (if there's one bound variable and it is not given an explicit type).
+bool IsExistentialGuard() {
+ scanner.ResetPeek();
+ if (la.kind == _ident) {
+ Token x = scanner.Peek();
+ if (x.kind == _colon || x.kind == _comma || x.kind == _boredSmiley) {
+ return true;
+ } else if (x.kind == _lbrace) {
+ x = scanner.Peek();
+ return x.kind == _colon;
+ }
+ }
+ return false;
+}
+
bool IsLoopSpec() {
return la.kind == _invariant | la.kind == _decreases | la.kind == _modifies;
}
@@ -175,6 +297,9 @@ bool IsMapDisplay() {
bool IsIMapDisplay() {
return la.kind == _imap && scanner.Peek().kind == _lbracket;
}
+bool IsISetDisplay() {
+ return la.kind == _iset && scanner.Peek().kind == _lbrace;
+}
bool IsSuffix() {
return la.kind == _dot || la.kind == _lbracket || la.kind == _openparen;
@@ -296,6 +421,9 @@ bool IsGenericInstantiation() {
return false;
}
}
+/* Returns true if the next thing is of the form:
+ * "<" Type { "," Type } ">"
+ */
bool IsTypeList(ref IToken pt) {
if (pt.kind != _openAngleBracket) {
return false;
@@ -303,6 +431,10 @@ bool IsTypeList(ref IToken pt) {
pt = scanner.Peek();
return IsTypeSequence(ref pt, _closeAngleBracket);
}
+/* Returns true if the next thing is of the form:
+ * Type { "," Type }
+ * followed by an endBracketKind.
+ */
bool IsTypeSequence(ref IToken pt, int endBracketKind) {
while (true) {
if (!IsType(ref pt)) {
@@ -334,12 +466,13 @@ bool IsType(ref IToken pt) {
return true;
case _arrayToken:
case _set:
+ case _iset:
case _multiset:
case _seq:
case _map:
case _imap:
pt = scanner.Peek();
- return IsTypeList(ref pt);
+ return pt.kind != _openAngleBracket || IsTypeList(ref pt);
case _ident:
while (true) {
// invariant: next token is an ident
@@ -358,12 +491,24 @@ bool IsType(ref IToken pt) {
}
case _openparen:
pt = scanner.Peek();
+ if (pt.kind == _closeparen) {
+ // end of type list
+ pt = scanner.Peek();
+ return true;
+ }
return IsTypeSequence(ref pt, _closeparen);
default:
return false;
}
}
+
+bool IsDefaultImport() {
+ scanner.ResetPeek();
+ Token x = scanner.Peek(); // lookahead token again
+ return la.val == "default" && x.val != "export";
+}
+
/*--------------------------------------------------------------------------*/
CHARACTERS
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
@@ -416,6 +561,7 @@ TOKENS
object = "object".
string = "string".
set = "set".
+ iset = "iset".
multiset = "multiset".
seq = "seq".
map = "map".
@@ -439,6 +585,7 @@ TOKENS
comma = ','.
verticalbar = '|'.
doublecolon = "::".
+ boredSmiley = ":|".
bullet = '\u2022'.
dot = '.'.
semi = ';'.
@@ -479,17 +626,14 @@ IGNORE cr + lf + tab
/*------------------------------------------------------------------------*/
PRODUCTIONS
Dafny
-= (. ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;
- List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();
- ModuleDecl submodule;
+= (. List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();
// to support multiple files, create a default module only if theModule is null
DefaultModuleDecl defaultModule = (DefaultModuleDecl)((LiteralModuleDecl)theModule).ModuleDef;
// theModule should be a DefaultModuleDecl (actually, the singular DefaultModuleDecl)
- TraitDecl/*!*/ trait;
Contract.Assert(defaultModule != null);
.)
{ "include" stringToken (. {
- string parsedFile = t.filename;
+ string parsedFile = scanner.FullFilename;
bool isVerbatimString;
string includedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);
includedFile = Util.RemoveEscaping(includedFile, isVerbatimString);
@@ -503,15 +647,7 @@ Dafny
}
.)
}
- { SubModuleDecl<defaultModule, out submodule> (. defaultModule.TopLevelDecls.Add(submodule); .)
- | ClassDecl<defaultModule, out c> (. defaultModule.TopLevelDecls.Add(c); .)
- | DatatypeDecl<defaultModule, out dt> (. defaultModule.TopLevelDecls.Add(dt); .)
- | NewtypeDecl<defaultModule, out td> (. defaultModule.TopLevelDecls.Add(td); .)
- | OtherTypeDecl<defaultModule, out td> (. defaultModule.TopLevelDecls.Add(td); .)
- | IteratorDecl<defaultModule, out iter> (. defaultModule.TopLevelDecls.Add(iter); .)
- | TraitDecl<defaultModule, out trait> (. defaultModule.TopLevelDecls.Add(trait); .)
- | ClassMemberDecl<membersDefaultClass, false, !DafnyOptions.O.AllowGlobals>
- }
+ { TopDecl<defaultModule, membersDefaultClass, /* isTopLevel */ true, /* isAbstract */ false> }
(. // find the default class in the default module, then append membersDefaultClass to its member list
DefaultClassDecl defaultClass = null;
foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
@@ -527,44 +663,78 @@ Dafny
} .)
EOF
.
-SubModuleDecl<ModuleDefinition parent, out ModuleDecl submodule>
-= (. ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;
- Attributes attrs = null; IToken/*!*/ id;
- TraitDecl/*!*/ trait;
- List<MemberDecl/*!*/> namedModuleDefaultClassMembers = new List<MemberDecl>();;
+
+DeclModifier<ref DeclModifierData dmod>
+= ( "abstract" (. dmod.IsAbstract = true; CheckAndSetToken(ref dmod.AbstractToken); .)
+ | "ghost" (. dmod.IsGhost = true; CheckAndSetToken(ref dmod.GhostToken); .)
+ | "static" (. dmod.IsStatic = true; CheckAndSetToken(ref dmod.StaticToken); .)
+ | "protected" (. dmod.IsProtected = true; CheckAndSetToken(ref dmod.ProtectedToken); .)
+ | "extern" (. dmod.IsExtern = true; CheckAndSetToken(ref dmod.ExternToken); .)
+ [ stringToken (. bool isVerbatimString;
+ string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);
+ dmod.ExternName = new StringLiteralExpr(t, s, isVerbatimString);
+ .)
+ ]
+ )
+ .
+
+TopDecl<. ModuleDefinition module, List<MemberDecl/*!*/> membersDefaultClass, bool isTopLevel, bool isAbstract .>
+= (. DeclModifierData dmod = new DeclModifierData(); ModuleDecl submodule;
+ ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;
+ TraitDecl/*!*/ trait;
+ .)
+ { DeclModifier<ref dmod> }
+ ( SubModuleDecl<dmod, module, out submodule> (. module.TopLevelDecls.Add(submodule); .)
+ | ClassDecl<dmod, module, out c> (. module.TopLevelDecls.Add(c); .)
+ | DatatypeDecl<dmod, module, out dt> (. module.TopLevelDecls.Add(dt); .)
+ | NewtypeDecl<dmod, module, out td> (. module.TopLevelDecls.Add(td); .)
+ | OtherTypeDecl<dmod, module, out td> (. module.TopLevelDecls.Add(td); .)
+ | IteratorDecl<dmod, module, out iter> (. module.TopLevelDecls.Add(iter); .)
+ | TraitDecl<dmod, module, out trait> (. module.TopLevelDecls.Add(trait); .)
+ | ClassMemberDecl<dmod, membersDefaultClass, false, !DafnyOptions.O.AllowGlobals,
+ !isTopLevel && DafnyOptions.O.IronDafny && isAbstract>
+ ) .
+
+SubModuleDecl<DeclModifierData dmod, ModuleDefinition parent, out ModuleDecl submodule>
+= (. Attributes attrs = null; IToken/*!*/ id;
+ List<MemberDecl/*!*/> namedModuleDefaultClassMembers = new List<MemberDecl>();;
List<IToken> idRefined = null, idPath = null, idAssignment = null;
ModuleDefinition module;
- ModuleDecl sm;
submodule = null; // appease compiler
- bool isAbstract = false;
+ bool isAbstract = dmod.IsAbstract;
+ bool isExclusively = false;
bool opened = false;
+ CheckDeclModifiers(dmod, "Modules", AllowedDeclModifiers.Abstract | AllowedDeclModifiers.Extern);
.)
- ( [ "abstract" (. isAbstract = true; .) ]
- "module"
+ ( "module"
{ Attribute<ref attrs> }
NoUSIdent<out id>
+ (. EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false); .)
- [ "refines" QualifiedModuleName<out idRefined> ] (. module = new ModuleDefinition(id, id.val, isAbstract, false, idRefined == null ? null : idRefined, parent, attrs, false); .)
+ [ "exclusively" "refines" QualifiedModuleName<out idRefined> (. isExclusively = true; .)
+ | "refines" QualifiedModuleName<out idRefined> (. isExclusively = false; .) ]
+ (. module = new ModuleDefinition(id, id.val, isAbstract, false, isExclusively, idRefined == null ? null : idRefined, parent, attrs, false, this); .)
"{" (. module.BodyStartTok = t; .)
- { SubModuleDecl<module, out sm> (. module.TopLevelDecls.Add(sm); .)
- | ClassDecl<module, out c> (. module.TopLevelDecls.Add(c); .)
- | TraitDecl<module, out trait> (. module.TopLevelDecls.Add(trait); .)
- | DatatypeDecl<module, out dt> (. module.TopLevelDecls.Add(dt); .)
- | NewtypeDecl<module, out td> (. module.TopLevelDecls.Add(td); .)
- | OtherTypeDecl<module, out td> (. module.TopLevelDecls.Add(td); .)
- | IteratorDecl<module, out iter> (. module.TopLevelDecls.Add(iter); .)
- | ClassMemberDecl<namedModuleDefaultClassMembers, false, !DafnyOptions.O.AllowGlobals>
- }
- "}" (. module.BodyEndTok = t;
+ { TopDecl<module, namedModuleDefaultClassMembers, /* isTopLevel */ false, isAbstract>}
+ "}" (. module.BodyEndTok = t;
module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
submodule = new LiteralModuleDecl(module, parent); .)
|
"import" ["opened" (.opened = true;.)]
NoUSIdent<out id>
+ (. EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false); .)
[ "=" QualifiedModuleName<out idPath>
(. submodule = new AliasModuleDecl(idPath, id, parent, opened); .)
- | "as" QualifiedModuleName<out idPath> ["default" QualifiedModuleName<out idAssignment> ]
+ | "as" QualifiedModuleName<out idPath> [IF(IsDefaultImport()) "default" QualifiedModuleName<out idAssignment> ]
+ (. submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened);
+ errors.Warning(t, "\"import A as B\" has been deprecated; in the new syntax, it is \"import A:B\"");
+ .)
+ | ":" QualifiedModuleName<out idPath>
(. submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened); .)
+ | "." QualifiedModuleName<out idPath>
+ (. idPath.Insert(0, id);
+ submodule = new AliasModuleDecl(idPath, id, parent, opened);
+ .)
]
[ SYNC ";"
// This semi-colon used to be required, but it seems silly to have it.
@@ -578,6 +748,33 @@ SubModuleDecl<ModuleDefinition parent, out ModuleDecl submodule>
submodule = new AliasModuleDecl(idPath, id, parent, opened);
}
.)
+ | (.
+ bool isDefault = false;
+ bool includeBody;
+ IToken exportId;
+ List<ExportSignature> exports = new List<ExportSignature>();;
+ List<string> extends = new List<string>();
+ .)
+ ["default" (. isDefault = true; .) ]
+ "export"
+ NoUSIdent<out exportId>
+ ["extends"
+ NoUSIdent<out id>(. extends.Add(id.val); .)
+ {"," NoUSIdent<out id> (. extends.Add(id.val); .) }
+ ]
+ "{"
+ NoUSIdent<out id> (. includeBody = false; .)
+ ['+' (. includeBody = true; .)]
+ (. exports.Add(new ExportSignature(id, includeBody)); .)
+ { ","
+ NoUSIdent<out id> (. includeBody = false; .)
+ ['+' (. includeBody = true; .)]
+ (. exports.Add(new ExportSignature(id, includeBody)); .)
+ }
+ "}"
+ (.
+ submodule = new ModuleExportDecl(exportId, parent, isDefault, exports, extends);
+ .)
)
.
@@ -589,7 +786,8 @@ QualifiedModuleName<.out List<IToken> ids.>
}
.
-ClassDecl<ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>
+
+ClassDecl<DeclModifierData dmodClass, ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>
= (. Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out c) != null);
IToken/*!*/ id;
@@ -599,18 +797,23 @@ ClassDecl<ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>
List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>();
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
+ CheckDeclModifiers(dmodClass, "Classes", AllowedDeclModifiers.Extern);
+ DeclModifierData dmod;
.)
SYNC
"class"
{ Attribute<ref attrs> }
NoUSIdent<out id>
+ (. EncodeExternAsAttribute(dmodClass, ref attrs, id, /* needAxiom */ false); .)
[ GenericParameters<typeArgs> ]
["extends"
Type<out trait> (. traits.Add(trait); .)
{"," Type<out trait> (. traits.Add(trait); .) }
]
"{" (. bodyStart = t; .)
- { ClassMemberDecl<members, true, false>
+ { (. dmod = new DeclModifierData(); .)
+ { DeclModifier<ref dmod> }
+ ClassMemberDecl<dmod, members, true, false, false>
}
"}"
(. c = new ClassDecl(id, id.val, module, typeArgs, members, attrs, traits);
@@ -619,23 +822,27 @@ ClassDecl<ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>
.)
.
- TraitDecl<ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait>
- = (. Contract.Requires(module != null);
+TraitDecl<DeclModifierData dmodIn, ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait>
+ = (. Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out trait) != null);
+ CheckDeclModifiers(dmodIn, "Traits", AllowedDeclModifiers.None);
IToken/*!*/ id;
Attributes attrs = null;
List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>(); //traits should not support type parameters at the moment
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
+ DeclModifierData dmod;
.)
SYNC
"trait"
{ Attribute<ref attrs> }
NoUSIdent<out id>
[ GenericParameters<typeArgs> ]
- "{" (. bodyStart = t; .)
- { ClassMemberDecl<members, true, false>
- }
+ "{" (. bodyStart = t; .)
+ { (. dmod = new DeclModifierData(); .)
+ { DeclModifier<ref dmod> }
+ ClassMemberDecl<dmod, members, true, false, false>
+ }
"}"
(. trait = new TraitDecl(id, id.val, module, typeArgs, members, attrs);
trait.BodyStartTok = bodyStart;
@@ -643,44 +850,33 @@ ClassDecl<ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>
.)
.
-ClassMemberDecl<.List<MemberDecl> mm, bool allowConstructors, bool moduleLevelDecl.>
+ClassMemberDecl<. DeclModifierData dmod, List<MemberDecl> mm, bool allowConstructors, bool moduleLevelDecl, bool isWithinAbstractModule.>
= (. Contract.Requires(cce.NonNullElements(mm));
Method/*!*/ m;
Function/*!*/ f;
- MemberModifiers mmod = new MemberModifiers();
- IToken staticToken = null, protectedToken = null;
.)
- { "ghost" (. mmod.IsGhost = true; .)
- | "static" (. mmod.IsStatic = true; staticToken = t; .)
- | "protected" (. mmod.IsProtected = true; protectedToken = t; .)
- }
( (. if (moduleLevelDecl) {
SemErr(la, "fields are not allowed to be declared at the module level; instead, wrap the field in a 'class' declaration");
- mmod.IsStatic = false;
- mmod.IsProtected = false;
+ dmod.IsStatic = false;
}
.)
- FieldDecl<mmod, mm>
+ FieldDecl<dmod, mm>
| IF(IsFunctionDecl())
- (. if (moduleLevelDecl && staticToken != null) {
- errors.Warning(staticToken, "module-level functions are always non-instance, so the 'static' keyword is not allowed here");
- mmod.IsStatic = false;
+ (. if (moduleLevelDecl && dmod.StaticToken != null) {
+ errors.Warning(dmod.StaticToken, "module-level functions are always non-instance, so the 'static' keyword is not allowed here");
+ dmod.IsStatic = false;
}
.)
- FunctionDecl<mmod, out f> (. mm.Add(f); .)
- | (. if (moduleLevelDecl && staticToken != null) {
- errors.Warning(staticToken, "module-level methods are always non-instance, so the 'static' keyword is not allowed here");
- mmod.IsStatic = false;
- }
- if (protectedToken != null) {
- SemErr(protectedToken, "only functions, not methods, can be declared 'protected'");
- mmod.IsProtected = false;
+ FunctionDecl<dmod, isWithinAbstractModule, out f> (. mm.Add(f); .)
+ | (. if (moduleLevelDecl && dmod.StaticToken != null) {
+ errors.Warning(dmod.StaticToken, "module-level methods are always non-instance, so the 'static' keyword is not allowed here");
+ dmod.IsStatic = false;
}
.)
- MethodDecl<mmod, allowConstructors, out m> (. mm.Add(m); .)
+ MethodDecl<dmod, allowConstructors, isWithinAbstractModule, out m> (. mm.Add(m); .)
)
.
-DatatypeDecl<ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt>
+DatatypeDecl<DeclModifierData dmod, ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt>
= (. Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out dt)!=null);
IToken/*!*/ id;
@@ -689,6 +885,7 @@ DatatypeDecl<ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt>
List<DatatypeCtor/*!*/> ctors = new List<DatatypeCtor/*!*/>();
IToken bodyStart = Token.NoToken; // dummy assignment
bool co = false;
+ CheckDeclModifiers(dmod, "Datatypes or codatatypes", AllowedDeclModifiers.None);
.)
SYNC
( "datatype"
@@ -726,27 +923,27 @@ DatatypeMemberDecl<.List<DatatypeCtor/*!*/>/*!*/ ctors.>
[ FormalsOptionalIds<formals> ]
(. ctors.Add(new DatatypeCtor(id, id.val, formals, attrs)); .)
.
-FieldDecl<.MemberModifiers mmod, List<MemberDecl/*!*/>/*!*/ mm.>
+FieldDecl<.DeclModifierData dmod, List<MemberDecl/*!*/>/*!*/ mm.>
= (. Contract.Requires(cce.NonNullElements(mm));
Attributes attrs = null;
IToken/*!*/ id; Type/*!*/ ty;
+ CheckDeclModifiers(dmod, "Fields", AllowedDeclModifiers.Ghost);
.)
SYNC
"var"
- (. if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); }
- .)
{ Attribute<ref attrs> }
- FIdentType<out id, out ty> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
- { "," FIdentType<out id, out ty> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
+ FIdentType<out id, out ty> (. mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs)); .)
+ { "," FIdentType<out id, out ty> (. mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs)); .)
}
OldSemi
.
-NewtypeDecl<ModuleDefinition module, out TopLevelDecl td>
+NewtypeDecl<DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td>
= (. IToken id, bvId;
Attributes attrs = null;
td = null;
Type baseType = null;
Expression wh;
+ CheckDeclModifiers(dmod, "Newtypes", AllowedDeclModifiers.None);
.)
"newtype"
{ Attribute<ref attrs> }
@@ -754,19 +951,20 @@ NewtypeDecl<ModuleDefinition module, out TopLevelDecl td>
"="
( IF(IsIdentColonOrBar())
NoUSIdent<out bvId>
- [ ":" Type<out baseType> ] (. if (baseType == null) { baseType = new OperationTypeProxy(true, true, false, false, false); } .)
+ [ ":" Type<out baseType> ] (. if (baseType == null) { baseType = new OperationTypeProxy(true, true, false, false, false, false); } .)
"|"
Expression<out wh, false, true> (. td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, new BoundVar(bvId, bvId.val, baseType), wh, attrs); .)
| Type<out baseType> (. td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, baseType, attrs); .)
)
.
-OtherTypeDecl<ModuleDefinition module, out TopLevelDecl td>
+OtherTypeDecl<DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td>
= (. IToken id;
Attributes attrs = null;
var eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
var typeArgs = new List<TypeParameter>();
td = null;
Type ty;
+ CheckDeclModifiers(dmod, "Type aliases", AllowedDeclModifiers.None);
.)
"type"
{ Attribute<ref attrs> }
@@ -862,7 +1060,7 @@ TypeIdentOptional<out IToken/*!*/ id, out string/*!*/ identName, out Type/*!*/ t
.)
.
/*------------------------------------------------------------------------*/
-IteratorDecl<ModuleDefinition module, out IteratorDecl/*!*/ iter>
+IteratorDecl<DeclModifierData dmod, ModuleDefinition module, out IteratorDecl/*!*/ iter>
= (. Contract.Ensures(Contract.ValueAtReturn(out iter) != null);
IToken/*!*/ id;
Attributes attrs = null;
@@ -884,6 +1082,7 @@ IteratorDecl<ModuleDefinition module, out IteratorDecl/*!*/ iter>
IToken signatureEllipsis = null;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ CheckDeclModifiers(dmod, "Iterators", AllowedDeclModifiers.None);
.)
SYNC
"iterator"
@@ -929,7 +1128,7 @@ GenericParameters<.List<TypeParameter/*!*/>/*!*/ typeArgs.>
">"
.
/*------------------------------------------------------------------------*/
-MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
+MethodDecl<DeclModifierData dmod, bool allowConstructor, bool isWithinAbstractModule, out Method/*!*/ m>
= (. Contract.Ensures(Contract.ValueAtReturn(out m) !=null);
IToken/*!*/ id = Token.NoToken;
bool hasName = false; IToken keywordToken;
@@ -951,43 +1150,36 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
IToken signatureEllipsis = null;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ AllowedDeclModifiers allowed = AllowedDeclModifiers.None;
+ string caption = "";
.)
SYNC
- ( "method"
- | "lemma" (. isLemma = true; .)
- | "colemma" (. isCoLemma = true; .)
- | "comethod" (. isCoLemma = true;
+ ( "method" (. caption = "Methods";
+ allowed = AllowedDeclModifiers.Ghost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Extern; .)
+ | "lemma" (. isLemma = true; caption = "Lemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected; .)
+ | "colemma" (. isCoLemma = true; caption = "Colemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected; .)
+ | "comethod" (. isCoLemma = true; caption = "Comethods";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected;
errors.Warning(t, "the 'comethod' keyword has been deprecated; it has been renamed to 'colemma'");
.)
- | "inductive" "lemma" (. isIndLemma = true; .)
+ | "inductive" "lemma" (. isIndLemma = true; caption = "Inductive lemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static;.)
| "constructor" (. if (allowConstructor) {
isConstructor = true;
} else {
SemErr(t, "constructors are allowed only in classes");
- }
+ }
+ caption = "Constructors";
+ allowed = AllowedDeclModifiers.None;
.)
- ) (. keywordToken = t; .)
- (. if (isLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "lemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- } else if (isConstructor) {
- if (mmod.IsGhost) {
- SemErr(t, "constructors cannot be declared 'ghost'");
- }
- if (mmod.IsStatic) {
- SemErr(t, "constructors cannot be declared 'static'");
- }
- } else if (isIndLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "inductive lemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- } else if (isCoLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "colemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- }
- .)
+ ) (. keywordToken = t;
+ CheckDeclModifiers(dmod, caption, allowed); .)
{ Attribute<ref attrs> }
[ NoUSIdent<out id> (. hasName = true; .)
]
@@ -997,12 +1189,13 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
SemErr(la, "a method must be given a name (expecting identifier)");
}
}
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true);
.)
(
[ GenericParameters<typeArgs> ]
- Formals<true, !mmod.IsGhost, ins>
+ Formals<true, !dmod.IsGhost, ins>
[ "returns" (. if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); } .)
- Formals<false, !mmod.IsGhost, outs>
+ Formals<false, !dmod.IsGhost, outs>
]
| "..." (. signatureEllipsis = t; .)
)
@@ -1010,7 +1203,7 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
[ BlockStmt<out body, out bodyStart, out bodyEnd>
]
(.
- if (DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported") && !Attributes.Contains(attrs, "decl") && theVerifyThisFile) {
+ if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported") && !Attributes.Contains(attrs, "decl") && theVerifyThisFile) {
SemErr(t, "a method with an ensures clause must have a body, unless given the :axiom attribute");
}
@@ -1019,16 +1212,16 @@ MethodDecl<MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m>
m = new Constructor(tok, hasName ? id.val : "_ctor", typeArgs, ins,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isIndLemma) {
- m = new InductiveLemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new InductiveLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isCoLemma) {
- m = new CoLemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new CoLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isLemma) {
- m = new Lemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new Lemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else {
- m = new Method(tok, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs,
+ m = new Method(tok, id.val, dmod.IsStatic, dmod.IsGhost, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
}
m.BodyStartTok = bodyStart;
@@ -1139,7 +1332,13 @@ TypeAndToken<out IToken tok, out Type ty>
[ GenericInstantiation<gt> ] (. if (gt.Count > 1) {
SemErr("set type expects only one type argument");
}
- ty = new SetType(gt.Count == 1 ? gt[0] : null);
+ ty = new SetType(true, gt.Count == 1 ? gt[0] : null);
+ .)
+ | "iset" (. tok = t; gt = new List<Type>(); .)
+ [ GenericInstantiation<gt> ] (. if (gt.Count > 1) {
+ SemErr("set type expects only one type argument");
+ }
+ ty = new SetType(false, gt.Count == 1 ? gt[0] : null);
.)
| "multiset" (. tok = t; gt = new List<Type>(); .)
[ GenericInstantiation<gt> ] (. if (gt.Count > 1) {
@@ -1227,7 +1426,7 @@ GenericInstantiation<.List<Type/*!*/>/*!*/ gt.>
">"
.
/*------------------------------------------------------------------------*/
-FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
+FunctionDecl<DeclModifierData dmod, bool isWithinAbstractModule, out Function/*!*/ f>
= (. Contract.Ensures(Contract.ValueAtReturn(out f)!=null);
Attributes attrs = null;
IToken/*!*/ id = Token.NoToken; // to please compiler
@@ -1250,7 +1449,13 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
( "function"
[ "method" (. isFunctionMethod = true; .)
]
- (. if (mmod.IsGhost) { SemErr(t, "functions cannot be declared 'ghost' (they are ghost by default)"); }
+ (. AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected;
+ string caption = "Functions";
+ if (isFunctionMethod) {
+ allowed |= AllowedDeclModifiers.Extern;
+ caption = "Function methods";
+ }
+ CheckDeclModifiers(dmod, caption, allowed);
.)
{ Attribute<ref attrs> }
NoUSIdent<out id>
@@ -1266,7 +1471,13 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
| "predicate" (. isPredicate = true; .)
[ "method" (. isFunctionMethod = true; .)
]
- (. if (mmod.IsGhost) { SemErr(t, "predicates cannot be declared 'ghost' (they are ghost by default)"); }
+ (. AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected;
+ string caption = "Predicates";
+ if (isFunctionMethod) {
+ allowed |= AllowedDeclModifiers.Extern;
+ caption = "Predicate methods";
+ }
+ CheckDeclModifiers(dmod, caption, allowed);
.)
{ Attribute<ref attrs> }
NoUSIdent<out id>
@@ -1281,7 +1492,8 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
/* ----- inductive predicate ----- */
| "inductive" "predicate" (. isIndPredicate = true; .)
- (. if (mmod.IsGhost) { SemErr(t, "inductive predicates cannot be declared 'ghost' (they are ghost by default)"); }
+ (. CheckDeclModifiers(dmod, "Inductive predicates",
+ AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);
.)
{ Attribute<ref attrs> }
NoUSIdent<out id>
@@ -1295,7 +1507,8 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
/* ----- copredicate ----- */
| "copredicate" (. isCoPredicate = true; .)
- (. if (mmod.IsGhost) { SemErr(t, "copredicates cannot be declared 'ghost' (they are ghost by default)"); }
+ (. CheckDeclModifiers(dmod, "Copredicates",
+ AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);
.)
{ Attribute<ref attrs> }
NoUSIdent<out id>
@@ -1312,22 +1525,23 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
{ FunctionSpec<reqs, reads, ens, decreases> }
[ FunctionBody<out body, out bodyStart, out bodyEnd>
]
- (. if (DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported")) {
+ (. if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 &&
+ !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported")) {
SemErr(t, "a function with an ensures clause must have a body, unless given the :axiom attribute");
}
-
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true);
IToken tok = theVerifyThisFile ? id : new IncludeToken(id);
if (isPredicate) {
- f = new Predicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, !isFunctionMethod, typeArgs, formals,
+ f = new Predicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureEllipsis);
} else if (isIndPredicate) {
- f = new InductivePredicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, typeArgs, formals,
+ f = new InductivePredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals,
reqs, reads, ens, body, attrs, signatureEllipsis);
} else if (isCoPredicate) {
- f = new CoPredicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, typeArgs, formals,
+ f = new CoPredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals,
reqs, reads, ens, body, attrs, signatureEllipsis);
} else {
- f = new Function(tok, id.val, mmod.IsStatic, mmod.IsProtected, !isFunctionMethod, typeArgs, formals, returnType,
+ f = new Function(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals, returnType,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);
}
f.BodyStartTok = bodyStart;
@@ -1582,50 +1796,78 @@ VarDeclStatement<.out Statement/*!*/ s.>
Expression suchThat = null;
Attributes attrs = null;
IToken endTok;
+ s = dummyStmt;
.)
[ "ghost" (. isGhost = true; x = t; .)
]
"var" (. if (!isGhost) { x = t; } .)
- { Attribute<ref attrs> }
- LocalIdentTypeOptional<out d, isGhost> (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)
- { ","
- { Attribute<ref attrs> }
- LocalIdentTypeOptional<out d, isGhost> (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)
- }
- [ ":=" (. assignTok = t; .)
- Rhs<out r> (. rhss.Add(r); .)
- { "," Rhs<out r> (. rhss.Add(r); .)
+ ( { Attribute<ref attrs> }
+ LocalIdentTypeOptional<out d, isGhost> (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)
+ { ","
+ { Attribute<ref attrs> }
+ LocalIdentTypeOptional<out d, isGhost> (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)
}
- | { Attribute<ref attrs> }
- ":|" (. assignTok = t; .)
- [ IF(la.kind == _assume) /* an Expression can also begin with an "assume", so this says to resolve it to pick up any "assume" here */
- "assume" (. suchThatAssume = t; .)
+ [ ":=" (. assignTok = t; .)
+ Rhs<out r> (. rhss.Add(r); .)
+ { "," Rhs<out r> (. rhss.Add(r); .)
+ }
+ | { Attribute<ref attrs> }
+ ":|" (. assignTok = t; .)
+ [ IF(la.kind == _assume) /* an Expression can also begin with an "assume", so this says to resolve it to pick up any "assume" here */
+ "assume" (. suchThatAssume = t; .)
+ ]
+ Expression<out suchThat, false, true>
]
- Expression<out suchThat, false, true>
- ]
- SYNC ";" (. endTok = t; .)
- (. ConcreteUpdateStatement update;
- if (suchThat != null) {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
- }
- update = new AssignSuchThatStmt(assignTok, endTok, ies, suchThat, suchThatAssume, attrs);
- } else if (rhss.Count == 0) {
- update = null;
- } else {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
+ SYNC ";" (. endTok = t; .)
+ (. ConcreteUpdateStatement update;
+ if (suchThat != null) {
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new AssignSuchThatStmt(assignTok, endTok, ies, suchThat, suchThatAssume, attrs);
+ } else if (rhss.Count == 0) {
+ update = null;
+ } else {
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new UpdateStmt(assignTok, endTok, ies, rhss);
}
- update = new UpdateStmt(assignTok, endTok, ies, rhss);
- }
- s = new VarDeclStmt(x, endTok, lhss, update);
- .)
+ s = new VarDeclStmt(x, endTok, lhss, update);
+ .)
+ | "(" (. var letLHSs = new List<CasePattern>();
+ var letRHSs = new List<Expression>();
+ List<CasePattern> arguments = new List<CasePattern>();
+ CasePattern pat;
+ Expression e = dummyExpr;
+ IToken id = t;
+ .)
+ [ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ]
+ ")" (. // Parse parenthesis without an identifier as a built in tuple type.
+ theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists
+ string ctor = BuiltIns.TupleTypeCtorName; //use the TupleTypeCtors
+ pat = new CasePattern(id, ctor, arguments);
+ if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }
+ letLHSs.Add(pat);
+ .)
+ ( ":="
+ | { Attribute<ref attrs> }
+ ":|" (. SemErr(pat.tok, "LHS of assign-such-that expression must be variables, not general patterns"); .)
+ )
+ Expression<out e, false, true> (. letRHSs.Add(e); .)
+
+ ";"
+ (. s = new LetStmt(e.tok, e.tok, letLHSs, letRHSs); .)
+ )
.
IfStmt<out Statement/*!*/ ifStmt>
= (. Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;
- Expression guard = null; IToken guardEllipsis = null;
+ Expression guard = null; IToken guardEllipsis = null; bool isExistentialGuard = false;
BlockStmt/*!*/ thn;
BlockStmt/*!*/ bs;
Statement/*!*/ s;
@@ -1637,11 +1879,13 @@ IfStmt<out Statement/*!*/ ifStmt>
"if" (. x = t; .)
(
IF(IsAlternative())
- AlternativeBlock<out alternatives, out endTok>
+ AlternativeBlock<true, out alternatives, out endTok>
(. ifStmt = new AlternativeStmt(x, endTok, alternatives); .)
|
- ( Guard<out guard>
- | "..." (. guardEllipsis = t; .)
+ ( IF(IsExistentialGuard())
+ ExistentialGuard<out guard, true> (. isExistentialGuard = true; .)
+ | Guard<out guard>
+ | "..." (. guardEllipsis = t; .)
)
BlockStmt<out thn, out bodyStart, out bodyEnd> (. endTok = thn.EndTok; .)
[ "else"
@@ -1650,26 +1894,29 @@ IfStmt<out Statement/*!*/ ifStmt>
)
]
(. if (guardEllipsis != null) {
- ifStmt = new SkeletonStatement(new IfStmt(x, endTok, guard, thn, els), guardEllipsis, null);
+ ifStmt = new SkeletonStatement(new IfStmt(x, endTok, isExistentialGuard, guard, thn, els), guardEllipsis, null);
} else {
- ifStmt = new IfStmt(x, endTok, guard, thn, els);
+ ifStmt = new IfStmt(x, endTok, isExistentialGuard, guard, thn, els);
}
.)
)
.
-AlternativeBlock<.out List<GuardedAlternative> alternatives, out IToken endTok.>
+AlternativeBlock<.bool allowExistentialGuards, out List<GuardedAlternative> alternatives, out IToken endTok.>
= (. alternatives = new List<GuardedAlternative>();
IToken x;
- Expression e;
+ Expression e; bool isExistentialGuard;
List<Statement> body;
.)
"{"
- { "case" (. x = t; .)
- Expression<out e, true, false> // NB: don't allow lambda here
+ { "case" (. x = t; isExistentialGuard = false; e = dummyExpr; .)
+ ( IF(allowExistentialGuards && IsExistentialGuard())
+ ExistentialGuard<out e, false > (. isExistentialGuard = true; .) // NB: don't allow lambda here
+ | Expression<out e, true, false> // NB: don't allow lambda here
+ )
"=>"
(. body = new List<Statement>(); .)
{ Stmt<body> }
- (. alternatives.Add(new GuardedAlternative(x, e, body)); .)
+ (. alternatives.Add(new GuardedAlternative(x, isExistentialGuard, e, body)); .)
}
"}" (. endTok = t; .)
.
@@ -1693,7 +1940,7 @@ WhileStmt<out Statement stmt>
(
IF(IsLoopSpec() || IsAlternative())
{ LoopSpec<invariants, decreases, ref mod, ref decAttrs, ref modAttrs> }
- AlternativeBlock<out alternatives, out endTok>
+ AlternativeBlock<false, out alternatives, out endTok>
(. stmt = new AlternativeLoopStmt(x, endTok, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), alternatives); .)
|
( Guard<out guard> (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)
@@ -1773,6 +2020,21 @@ Guard<out Expression e> /* null represents demonic-choice */
| Expression<out ee, true, true> (. e = ee; .)
)
.
+ExistentialGuard<out Expression e, bool allowLambda>
+= (. var bvars = new List<BoundVar>();
+ BoundVar bv; IToken x;
+ Attributes attrs = null;
+ Expression body;
+ .)
+ IdentTypeOptional<out bv> (. bvars.Add(bv); x = bv.tok; .)
+ { ","
+ IdentTypeOptional<out bv> (. bvars.Add(bv); .)
+ }
+ { Attribute<ref attrs> }
+ ":|"
+ Expression<out body, true, allowLambda>
+ (. e = new ExistsExpr(x, bvars, null, body, attrs); .)
+ .
MatchStmt<out Statement/*!*/ s>
= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x; Expression/*!*/ e; MatchCaseStmt/*!*/ c;
@@ -1794,17 +2056,25 @@ MatchStmt<out Statement/*!*/ s>
CaseStatement<out MatchCaseStmt/*!*/ c>
= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null);
IToken/*!*/ x, id;
- List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
- BoundVar/*!*/ bv;
+ List<CasePattern/*!*/> arguments = new List<CasePattern/*!*/>();
+ CasePattern/*!*/ pat;
List<Statement/*!*/> body = new List<Statement/*!*/>();
+ string/*!*/ name = "";
.)
"case" (. x = t; .)
- Ident<out id>
- [ "("
- IdentTypeOptional<out bv> (. arguments.Add(bv); .)
- { "," IdentTypeOptional<out bv> (. arguments.Add(bv); .)
- }
- ")" ]
+ ( Ident<out id> (. name = id.val; .)
+ [ "("
+ [ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ]
+ ")" ]
+ | "("
+ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ")"
+ )
"=>"
SYNC /* this SYNC and the one inside the loop below are used to avoid problems with the IsNotEndOfCase test. The SYNC will
* skip until the next symbol that can legally occur here, which is either the beginning of a Stmt or whatever is allowed
@@ -1814,7 +2084,7 @@ CaseStatement<out MatchCaseStmt/*!*/ c>
Stmt<body>
SYNC /* see comment about SYNC above */
}
- (. c = new MatchCaseStmt(x, id.val, arguments, body); .)
+ (. c = new MatchCaseStmt(x, name, arguments, body); .)
.
/*------------------------------------------------------------------------*/
AssertStmt<out Statement/*!*/ s>
@@ -1947,6 +2217,7 @@ ModifyStmt<out Statement s>
CalcStmt<out Statement s>
= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x;
+ Attributes attrs = null;
CalcStmt.CalcOp op, calcOp = Microsoft.Dafny.CalcStmt.DefaultOp, resOp = Microsoft.Dafny.CalcStmt.DefaultOp;
var lines = new List<Expression>();
var hints = new List<BlockStmt>();
@@ -1958,6 +2229,7 @@ CalcStmt<out Statement s>
IToken danglingOperator = null;
.)
"calc" (. x = t; .)
+ { IF(IsAttribute()) Attribute<ref attrs> }
[ CalcOp<out opTok, out calcOp> (. maybeOp = calcOp.ResultOp(calcOp); // guard against non-transitive calcOp (like !=)
if (maybeOp == null) {
SemErr(opTok, "the main operator of a calculation must be transitive");
@@ -2006,7 +2278,7 @@ CalcStmt<out Statement s>
// Repeat the last line to create a dummy line for the dangling hint
lines.Add(lines[lines.Count - 1]);
}
- s = new CalcStmt(x, t, calcOp, lines, hints, stepOps, resOp);
+ s = new CalcStmt(x, t, calcOp, lines, hints, stepOps, resOp, attrs);
.)
.
CalcOp<out IToken x, out CalcStmt.CalcOp/*!*/ op>
@@ -2100,10 +2372,13 @@ ImpliesExpliesExpression<out Expression e0, bool allowSemi, bool allowLambda>
( ImpliesOp (. x = t; .)
ImpliesExpression<out e1, allowSemi, allowLambda> (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Imp, e0, e1); .)
| ExpliesOp (. x = t; .)
- LogicalExpression<out e1, allowSemi, allowLambda> (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e0, e1); .)
+ LogicalExpression<out e1, allowSemi, allowLambda> (. // The order of operands is reversed so that it can be turned into implication during resolution
+ e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0); .)
{ IF(IsExpliesOp()) /* read a reverse implication as far as possible */
ExpliesOp (. x = t; .)
- LogicalExpression<out e1, allowSemi, allowLambda> (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e0, e1); .)
+ LogicalExpression<out e1, allowSemi, allowLambda> (. //The order of operands is reversed so that it can be turned into implication during resolution
+ e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0);
+ .)
}
)
]
@@ -2317,10 +2592,13 @@ UnaryExpression<out Expression e, bool allowSemi, bool allowLambda>
"imap" (. x = t; .)
MapDisplayExpr<x, false, out e>
{ IF(IsSuffix()) Suffix<ref e> }
+ | IF(IsISetDisplay()) /* this alternative must be checked before going into EndlessExpression, where there is another "iset" */
+ "iset" (. x = t; .)
+ ISetDisplayExpr<x, false, out e>
+ { IF(IsSuffix()) Suffix<ref e> }
| IF(IsLambda(allowLambda))
LambdaExpression<out e, allowSemi> /* this is an endless expression */
| EndlessExpression<out e, allowSemi, allowLambda>
-
| NameSegment<out e>
{ IF(IsSuffix()) Suffix<ref e> }
| DisplayExpr<out e>
@@ -2425,13 +2703,22 @@ ParensExpression<out Expression e, bool allowSemi, bool allowLambda>
}
.)
.
+ISetDisplayExpr<IToken/*!*/ setToken, bool finite, out Expression e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ List<Expression> elements = new List<Expression/*!*/>();;
+ e = dummyExpr;
+ .)
+ "{"
+ [ Expressions<elements> ] (. e = new SetDisplayExpr(setToken, finite, elements);.)
+ "}"
+ .
DisplayExpr<out Expression e>
= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
IToken x; List<Expression> elements;
e = dummyExpr;
.)
( "{" (. x = t; elements = new List<Expression/*!*/>(); .)
- [ Expressions<elements> ] (. e = new SetDisplayExpr(x, elements);.)
+ [ Expressions<elements> ] (. e = new SetDisplayExpr(x, true, elements);.)
"}"
| "[" (. x = t; elements = new List<Expression/*!*/>(); .)
[ Expressions<elements> ] (. e = new SeqDisplayExpr(x, elements); .)
@@ -2496,7 +2783,10 @@ EndlessExpression<out Expression e, bool allowSemi, bool allowLambda>
"else" Expression<out e1, allowSemi, allowLambda> (. e = new ITEExpr(x, e, e0, e1); .)
| MatchExpression<out e, allowSemi, allowLambda>
| QuantifierGuts<out e, allowSemi, allowLambda>
- | SetComprehensionExpr<out e, allowSemi, allowLambda>
+ | "set" (. x = t; .)
+ SetComprehensionExpr<x, true, out e, allowSemi, allowLambda>
+ | "iset" (. x = t; .)
+ SetComprehensionExpr<x, false, out e, allowSemi, allowLambda>
| StmtInExpr<out s>
Expression<out e, allowSemi, allowLambda> (. e = new StmtExpr(s.Tok, s, e); .)
| LetExpr<out e, allowSemi, allowLambda>
@@ -2584,19 +2874,27 @@ MatchExpression<out Expression e, bool allowSemi, bool allowLambda>
.
CaseExpression<out MatchCaseExpr c, bool allowSemi, bool allowLambda>
= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ x, id;
- List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
- BoundVar/*!*/ bv;
+ List<CasePattern/*!*/> arguments = new List<CasePattern/*!*/>();
+ CasePattern/*!*/ pat;
Expression/*!*/ body;
+ string/*!*/ name = "";
.)
"case" (. x = t; .)
- Ident<out id>
- [ "("
- IdentTypeOptional<out bv> (. arguments.Add(bv); .)
- { "," IdentTypeOptional<out bv> (. arguments.Add(bv); .)
- }
- ")" ]
+ ( Ident<out id> (. name = id.val; .)
+ [ "("
+ [ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ]
+ ")" ]
+ | "("
+ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ")"
+ )
"=>"
- Expression<out body, allowSemi, allowLambda> (. c = new MatchCaseExpr(x, id.val, arguments, body); .)
+ Expression<out body, allowSemi, allowLambda> (. c = new MatchCaseExpr(x, name, arguments, body); .)
.
CasePattern<out CasePattern pat>
= (. IToken id; List<CasePattern> arguments;
@@ -2611,7 +2909,18 @@ CasePattern<out CasePattern pat>
}
]
")" (. pat = new CasePattern(id, id.val, arguments); .)
-
+ | "(" (. id = t;
+ arguments = new List<CasePattern>();
+ .)
+ [ CasePattern<out pat> (. arguments.Add(pat); .)
+ { "," CasePattern<out pat> (. arguments.Add(pat); .)
+ }
+ ]
+ ")" (. // Parse parenthesis without an identifier as a built in tuple type.
+ theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists
+ string ctor = BuiltIns.TupleTypeCtorName; //use the TupleTypeCtors
+ pat = new CasePattern(id, ctor, arguments);
+ .)
| IdentTypeOptional<out bv> (. // This could be a BoundVar of a parameter-less constructor and we may not know until resolution.
// Nevertheless, we do put the "bv" into the CasePattern here (even though it will get thrown out
// later if resolution finds the CasePattern to denote a parameter-less constructor), because this
@@ -2683,8 +2992,17 @@ Suffix<ref Expression e>
Expression e0 = null; Expression e1 = null; Expression ee; bool anyDots = false;
List<Expression> multipleLengths = null; bool takeRest = false; // takeRest is relevant only if multipleLengths is non-null
List<Expression> multipleIndices = null;
+ List<Tuple<IToken, string, Expression>> updates;
+ Expression v;
.)
- ( DotSuffix<out id, out x> (. if (x != null) {
+ ( "."
+ ( "(" (. x = t; updates = new List<Tuple<IToken, string, Expression>>(); .)
+ MemberBindingUpdate<out id, out v> (. updates.Add(Tuple.Create(id, id.val, v)); .)
+ { "," MemberBindingUpdate<out id, out v> (. updates.Add(Tuple.Create(id, id.val, v)); .)
+ }
+ ")"
+ (. e = new DatatypeUpdateExpr(x, e, updates); .)
+ | DotSuffix<out id, out x> (. if (x != null) {
// process id as a Suffix in its own right
e = new ExprDotName(id, e, id.val, null);
id = x; // move to the next Suffix
@@ -2693,17 +3011,18 @@ Suffix<ref Expression e>
.)
- ( IF(IsGenericInstantiation())
- (. typeArgs = new List<Type>(); .)
- GenericInstantiation<typeArgs>
- | HashCall<id, out openParen, out typeArgs, out args>
- | /* empty */
+ ( IF(IsGenericInstantiation())
+ (. typeArgs = new List<Type>(); .)
+ GenericInstantiation<typeArgs>
+ | HashCall<id, out openParen, out typeArgs, out args>
+ | /* empty */
+ )
+ (. e = new ExprDotName(id, e, id.val, typeArgs);
+ if (openParen != null) {
+ e = new ApplySuffix(openParen, e, args);
+ }
+ .)
)
- (. e = new ExprDotName(id, e, id.val, typeArgs);
- if (openParen != null) {
- e = new ApplySuffix(openParen, e, args);
- }
- .)
| "[" (. x = t; .)
( Expression<out ee, true, true> (. e0 = ee; .)
( ".." (. anyDots = true; .)
@@ -2817,16 +3136,14 @@ QuantifierDomain<.out List<BoundVar> bvars, out Attributes attrs, out Expression
]
.
-SetComprehensionExpr<out Expression q, bool allowSemi, bool allowLambda>
+SetComprehensionExpr<IToken setToken, bool finite, out Expression q, bool allowSemi, bool allowLambda>
= (. Contract.Ensures(Contract.ValueAtReturn(out q) != null);
- IToken x = Token.NoToken;
BoundVar bv;
List<BoundVar/*!*/> bvars = new List<BoundVar>();
Expression range;
Expression body = null;
Attributes attrs = null;
.)
- "set" (. x = t; .)
IdentTypeOptional<out bv> (. bvars.Add(bv); .)
{ ","
IdentTypeOptional<out bv> (. bvars.Add(bv); .)
@@ -2838,7 +3155,7 @@ SetComprehensionExpr<out Expression q, bool allowSemi, bool allowLambda>
Expression<out body, allowSemi, allowLambda>
]
(. if (body == null && bvars.Count != 1) { SemErr(t, "a set comprehension with more than one bound variable must have a term expression"); }
- q = new SetComprehension(x, bvars, range, body, attrs);
+ q = new SetComprehension(setToken, finite, bvars, range, body, attrs);
.)
.
Expressions<.List<Expression> args.>
@@ -2849,10 +3166,10 @@ Expressions<.List<Expression> args.>
.
/*------------------------------------------------------------------------*/
Attribute<ref Attributes attrs>
-= (. string name;
+= (. IToken x; string name;
var args = new List<Expression>();
.)
- "{" ":" ident (. name = t.val; .)
+ "{" ":" NoUSIdent<out x> (. name = x.val; .)
[ Expressions<args> ]
"}"
(. attrs = new Attributes(name, args, attrs); .)
@@ -2863,10 +3180,10 @@ Ident<out IToken/*!*/ x>
ident (. x = t; .)
.
// Identifier or sequence of digits
-// Parse one of the following:
-// . ident
-// . digits
-// . digits . digits
+// Parse one of the following, which are supposed to follow a ".":
+// ident
+// digits
+// digits . digits
// In the first two cases, x returns as the token for the ident/digits and y returns as null.
// In the third case, x and y return as the tokens for the first and second digits.
// This parser production solves a problem where the scanner might parse a real number instead
@@ -2876,7 +3193,6 @@ DotSuffix<out IToken x, out IToken y>
x = Token.NoToken;
y = null;
.)
- "."
( ident (. x = t; .)
| digits (. x = t; .)
| decimaldigits (. x = t;
@@ -2902,6 +3218,15 @@ DotSuffix<out IToken x, out IToken y>
| "reads" (. x = t; .)
)
.
+MemberBindingUpdate<out IToken id, out Expression e>
+= (. id = Token.NoToken; e = dummyExpr; .)
+ ( ident (. id = t; .)
+ | digits (. id = t; .)
+ )
+ ":="
+ Expression<out e, true, true>
+ .
+
// Identifier, disallowing leading underscores
NoUSIdent<out IToken/*!*/ x>
= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)
@@ -2933,7 +3258,7 @@ Nat<out BigInteger n>
( digits
(. S = Util.RemoveUnderscores(t.val);
try {
- n = BigInteger.Parse(S);
+ n = BigIntegerParser.Parse(S);
} catch (System.FormatException) {
SemErr("incorrectly formatted number");
n = BigInteger.Zero;
@@ -2943,7 +3268,7 @@ Nat<out BigInteger n>
(. S = Util.RemoveUnderscores(t.val.Substring(2));
try {
// note: leading 0 required when parsing positive hex numbers
- n = BigInteger.Parse("0" + S, System.Globalization.NumberStyles.HexNumber);
+ n = BigIntegerParser.Parse("0" + S, System.Globalization.NumberStyles.HexNumber);
} catch (System.FormatException) {
SemErr("incorrectly formatted number");
n = BigInteger.Zero;
diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs
index 99dfecd6..ab1a411a 100644
--- a/Source/Dafny/DafnyAst.cs
+++ b/Source/Dafny/DafnyAst.cs
@@ -10,6 +10,7 @@ using System.Diagnostics.Contracts;
using System.Numerics;
using System.Linq;
using Microsoft.Boogie;
+using System.Diagnostics;
namespace Microsoft.Dafny {
public class Program {
@@ -26,20 +27,22 @@ namespace Microsoft.Dafny {
public List<ModuleDefinition> CompileModules; // filled in during resolution.
// Contains the definitions to be used for compilation.
- List<AdditionalInformation> _additionalInformation = new List<AdditionalInformation>();
- public List<AdditionalInformation> AdditionalInformation { get { return _additionalInformation; } }
public readonly ModuleDecl DefaultModule;
public readonly ModuleDefinition DefaultModuleDef;
public readonly BuiltIns BuiltIns;
public readonly List<TranslationTask> TranslationTasks;
- public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns) {
+ public readonly ErrorReporter reporter;
+
+ public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns, ErrorReporter reporter) {
Contract.Requires(name != null);
Contract.Requires(module != null);
Contract.Requires(module is LiteralModuleDecl);
+ Contract.Requires(reporter != null);
FullName = name;
DefaultModule = module;
DefaultModuleDef = (DefaultModuleDecl)((LiteralModuleDecl)module).ModuleDef;
BuiltIns = builtIns;
+ this.reporter = reporter;
Modules = new List<ModuleDefinition>();
CompileModules = new List<ModuleDefinition>();
TranslationTasks = new List<TranslationTask>();
@@ -86,7 +89,7 @@ namespace Microsoft.Dafny {
public class BuiltIns
{
- public readonly ModuleDefinition SystemModule = new ModuleDefinition(Token.NoToken, "_System", false, false, null, null, null, true);
+ public readonly ModuleDefinition SystemModule = new ModuleDefinition(Token.NoToken, "_System", false, false, /*isExclusiveRefinement:*/ false, null, null, null, true);
readonly Dictionary<int, ClassDecl> arrayTypeDecls = new Dictionary<int, ClassDecl>();
readonly Dictionary<int, ArrowTypeDecl> arrowTypeDecls = new Dictionary<int, ArrowTypeDecl>();
readonly Dictionary<int, TupleTypeDecl> tupleTypeDecls = new Dictionary<int, TupleTypeDecl>();
@@ -165,7 +168,7 @@ namespace Microsoft.Dafny {
var argExprs = args.ConvertAll(a =>
(Expression)new IdentifierExpr(tok, a.Name) { Var = a, Type = a.Type });
var readsIS = new FunctionCallExpr(tok, "reads", new ImplicitThisExpr(tok), tok, argExprs) {
- Type = new SetType(new ObjectType()),
+ Type = new SetType(true, new ObjectType()),
};
var readsFrame = new List<FrameExpression> { new FrameExpression(tok, readsIS, null) };
var req = new Function(tok, "requires", false, false, true,
@@ -174,13 +177,13 @@ namespace Microsoft.Dafny {
new Specification<Expression>(new List<Expression>(), null),
null, null, null);
var reads = new Function(tok, "reads", false, false, true,
- new List<TypeParameter>(), args, new SetType(new ObjectType()),
+ new List<TypeParameter>(), args, new SetType(true, new ObjectType()),
new List<Expression>(), readsFrame, new List<Expression>(),
new Specification<Expression>(new List<Expression>(), null),
null, null, null);
readsIS.Function = reads; // just so we can really claim the member declarations are resolved
readsIS.TypeArgumentSubstitutions = Util.Dict(tps, tys); // ditto
- var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile());
+ var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile(), null);
arrowTypeDecls.Add(arity, arrowDecl);
SystemModule.TopLevelDecls.Add(arrowDecl);
}
@@ -232,21 +235,12 @@ namespace Microsoft.Dafny {
}
public static IEnumerable<Expression> SubExpressions(Attributes attrs) {
- for (; attrs != null; attrs = attrs.Prev) {
- foreach (var arg in attrs.Args) {
- yield return arg;
- }
- }
+ return attrs.AsEnumerable().SelectMany(aa => attrs.Args);
}
public static bool Contains(Attributes attrs, string nm) {
Contract.Requires(nm != null);
- for (; attrs != null; attrs = attrs.Prev) {
- if (attrs.Name == nm) {
- return true;
- }
- }
- return false;
+ return attrs.AsEnumerable().Any(aa => aa.Name == nm);
}
/// <summary>
@@ -258,10 +252,10 @@ namespace Microsoft.Dafny {
[Pure]
public static bool ContainsBool(Attributes attrs, string nm, ref bool value) {
Contract.Requires(nm != null);
- for (; attrs != null; attrs = attrs.Prev) {
- if (attrs.Name == nm) {
- if (attrs.Args.Count == 1) {
- var arg = attrs.Args[0] as LiteralExpr;
+ foreach (var attr in attrs.AsEnumerable()) {
+ if (attr.Name == nm) {
+ if (attr.Args.Count == 1) {
+ var arg = attr.Args[0] as LiteralExpr;
if (arg != null && arg.Value is bool) {
value = (bool)arg.Value;
}
@@ -306,12 +300,28 @@ namespace Microsoft.Dafny {
/// </summary>
public static List<Expression> FindExpressions(Attributes attrs, string nm) {
Contract.Requires(nm != null);
+ foreach (var attr in attrs.AsEnumerable()) {
+ if (attr.Name == nm) {
+ return attr.Args;
+ }
+ }
+ return null;
+ }
+
+
+ /// <summary>
+ /// Same as FindExpressions, but returns all matches
+ /// </summary>
+ public static List<List<Expression>> FindAllExpressions(Attributes attrs, string nm) {
+ Contract.Requires(nm != null);
+ List<List<Expression>> ret = null;
for (; attrs != null; attrs = attrs.Prev) {
if (attrs.Name == nm) {
- return attrs.Args;
+ ret = ret ?? new List<List<Expression>>(); // Avoid allocating the list in the common case where we don't find nm
+ ret.Add(attrs.Args);
}
}
- return null;
+ return ret;
}
/// <summary>
@@ -322,13 +332,13 @@ namespace Microsoft.Dafny {
/// - if "allowed" contains Int and Args contains one BigInteger literal, return true and set value to the BigInteger literal. Otherwise,
/// - if "allowed" contains String and Args contains one string literal, return true and set value to the string literal. Otherwise,
/// - if "allowed" contains Expression and Args contains one element, return true and set value to the one element (of type Expression). Otherwise,
- /// - return false, leave value unmodified, and call errorReporter with an error string.
+ /// - return false, leave value unmodified, and call reporter with an error string.
/// </summary>
public enum MatchingValueOption { Empty, Bool, Int, String, Expression }
- public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable<MatchingValueOption> allowed, Action<string> errorReporter) {
+ public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable<MatchingValueOption> allowed, Action<string> reporter) {
Contract.Requires(nm != null);
Contract.Requires(allowed != null);
- Contract.Requires(errorReporter != null);
+ Contract.Requires(reporter != null);
List<Expression> args = FindExpressions(attrs, nm);
if (args == null) {
return false;
@@ -336,7 +346,7 @@ namespace Microsoft.Dafny {
if (allowed.Contains(MatchingValueOption.Empty)) {
return true;
} else {
- errorReporter("Attribute " + nm + " requires one argument");
+ reporter("Attribute " + nm + " requires one argument");
return false;
}
} else if (args.Count == 1) {
@@ -356,16 +366,25 @@ namespace Microsoft.Dafny {
value = arg;
return true;
} else {
- errorReporter("Attribute " + nm + " expects an argument in one of the following categories: " + String.Join(", ", allowed));
+ reporter("Attribute " + nm + " expects an argument in one of the following categories: " + String.Join(", ", allowed));
return false;
}
} else {
- errorReporter("Attribute " + nm + " cannot have more than one argument");
+ reporter("Attribute " + nm + " cannot have more than one argument");
return false;
}
}
}
+ internal static class AttributesExtensions {
+ public static IEnumerable<Attributes> AsEnumerable(this Attributes attr) {
+ while (attr != null) {
+ yield return attr;
+ attr = attr.Prev;
+ }
+ }
+ }
+
// ------------------------------------------------------------------------------------------------------
public abstract class Type {
@@ -412,16 +431,33 @@ namespace Microsoft.Dafny {
var pt = type as TypeProxy;
if (pt != null && pt.T != null) {
type = pt.T;
- } else {
+ continue;
+ }
var syn = type.AsTypeSynonym;
if (syn != null) {
var udt = (UserDefinedType)type; // correctness of cast follows from the AsTypeSynonym != null test.
// Instantiate with the actual type arguments
type = syn.RhsWithArgument(udt.TypeArgs);
+ continue;
+ }
+ if (DafnyOptions.O.IronDafny && type is UserDefinedType) {
+ var rc = ((UserDefinedType)type).ResolvedClass;
+ if (rc != null) {
+ while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) {
+ if (rc.ClonedFrom != null) {
+ rc = (TopLevelDecl)rc.ClonedFrom;
} else {
- return type;
+ Contract.Assert(rc.ExclusiveRefinement != null);
+ rc = rc.ExclusiveRefinement;
+ }
+ }
+ }
+ if (rc is TypeSynonymDecl) {
+ type = ((TypeSynonymDecl)rc).Rhs;
+ continue;
}
}
+ return type;
}
}
@@ -490,6 +526,27 @@ namespace Microsoft.Dafny {
}
}
+ public bool HasFinitePossibleValues {
+ get {
+ if (IsBoolType || IsCharType || IsRefType) {
+ return true;
+ }
+ var st = AsSetType;
+ if (st != null && st.Arg.HasFinitePossibleValues) {
+ return true;
+ }
+ var mt = AsMapType;
+ if (mt != null && mt.Domain.HasFinitePossibleValues) {
+ return true;
+ }
+ var dt = AsDatatype;
+ if (dt != null && dt.HasFinitePossibleValues) {
+ return true;
+ }
+ return false;
+ }
+ }
+
public CollectionType AsCollectionType { get { return NormalizeExpand() as CollectionType; } }
public SetType AsSetType { get { return NormalizeExpand() as SetType; } }
public MultiSetType AsMultiSetType { get { return NormalizeExpand() as MultiSetType; } }
@@ -535,6 +592,12 @@ namespace Microsoft.Dafny {
return t != null && !t.Finite;
}
}
+ public bool IsISetType {
+ get {
+ var t = NormalizeExpand() as SetType;
+ return t != null && !t.Finite;
+ }
+ }
public NewtypeDecl AsNewtype {
get {
var udt = NormalizeExpand() as UserDefinedType;
@@ -633,7 +696,7 @@ namespace Microsoft.Dafny {
/// </summary>
public bool IsOrdered {
get {
- return !IsTypeParameter && !IsCoDatatype && !IsArrowType && !IsIMapType;
+ return !IsTypeParameter && !IsCoDatatype && !IsArrowType && !IsIMapType && !IsISetType;
}
}
@@ -859,17 +922,25 @@ namespace Microsoft.Dafny {
}
public class SetType : CollectionType {
- public SetType(Type arg) : base(arg) {
+ private bool finite;
+
+ public bool Finite {
+ get { return finite; }
+ set { finite = value; }
}
- public override string CollectionTypeName { get { return "set"; } }
+
+ public SetType(bool finite, Type arg) : base(arg) {
+ this.finite = finite;
+ }
+ public override string CollectionTypeName { get { return finite ? "set" : "iset"; } }
[Pure]
public override bool Equals(Type that) {
var t = that.NormalizeExpand() as SetType;
- return t != null && Arg.Equals(t.Arg);
+ return t != null && Finite == t.Finite && Arg.Equals(t.Arg);
}
public override bool PossiblyEquals_W(Type that) {
var t = that as SetType;
- return t != null && Arg.PossiblyEquals(t.Arg);
+ return t != null && Finite == t.Finite && Arg.PossiblyEquals(t.Arg);
}
}
@@ -988,7 +1059,7 @@ namespace Microsoft.Dafny {
public virtual string FullCompileName {
get {
if (ResolvedClass != null && !ResolvedClass.Module.IsDefaultModule) {
- return ResolvedClass.Module.CompileName + ".@" + CompileName;
+ return ResolvedClass.Module.CompileName + ".@" + ResolvedClass.CompileName;
} else {
return CompileName;
}
@@ -997,7 +1068,11 @@ namespace Microsoft.Dafny {
public string FullCompanionCompileName {
get {
Contract.Requires(ResolvedClass is TraitDecl);
- var s = ResolvedClass.Module.IsDefaultModule ? "" : ResolvedClass.Module.CompileName + ".";
+ var m = ResolvedClass.Module;
+ while (DafnyOptions.O.IronDafny && m.ClonedFrom != null) {
+ m = m.ClonedFrom;
+ }
+ var s = m.IsDefaultModule ? "" : m.CompileName + ".";
return s + "@_Companion_" + CompileName;
}
}
@@ -1312,20 +1387,22 @@ namespace Microsoft.Dafny {
/// <summary>
/// This proxy stands for:
- /// set(Arg) or multiset(Arg) or seq(Arg) or map(Arg, anyRange) or imap(Arg, anyRange)
+ /// set(Arg) or iset(Arg) or multiset(Arg) or seq(Arg) or map(Arg, anyRange) or imap(Arg, anyRange)
/// </summary>
public class CollectionTypeProxy : RestrictedTypeProxy {
public readonly Type Arg;
public readonly bool AllowIMap;
+ public readonly bool AllowISet;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Arg != null);
}
- public CollectionTypeProxy(Type arg, bool allowIMap) {
+ public CollectionTypeProxy(Type arg, bool allowIMap, bool allowISet) {
Contract.Requires(arg != null);
Arg = arg;
AllowIMap = allowIMap;
+ AllowISet = allowISet;
}
public override int OrderID {
get {
@@ -1338,6 +1415,7 @@ namespace Microsoft.Dafny {
/// This proxy can stand for any numeric type.
/// In addition, if AllowSeq, then it can stand for a seq.
/// In addition, if AllowSetVarieties, it can stand for a set or multiset.
+ /// In addition, if AllowISet, then it can stand for a iset
/// </summary>
public class OperationTypeProxy : RestrictedTypeProxy {
public readonly bool AllowInts;
@@ -1345,13 +1423,14 @@ namespace Microsoft.Dafny {
public readonly bool AllowChar;
public readonly bool AllowSeq;
public readonly bool AllowSetVarieties;
+ public readonly bool AllowISet;
public bool JustInts {
- get { return AllowInts && !AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties; }
+ get { return AllowInts && !AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties && !AllowISet; }
}
public bool JustReals {
- get { return !AllowInts && AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties; }
+ get { return !AllowInts && AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties && !AllowISet; }
}
- public OperationTypeProxy(bool allowInts, bool allowReals, bool allowChar, bool allowSeq, bool allowSetVarieties) {
+ public OperationTypeProxy(bool allowInts, bool allowReals, bool allowChar, bool allowSeq, bool allowSetVarieties, bool allowISet) {
Contract.Requires(allowInts || allowReals || allowChar || allowSeq || allowSetVarieties); // don't allow unsatisfiable constraint
Contract.Requires(!(!allowInts && !allowReals && allowChar && !allowSeq && !allowSetVarieties)); // to constrain to just char, don't use a proxy
AllowInts = allowInts;
@@ -1359,6 +1438,7 @@ namespace Microsoft.Dafny {
AllowChar = allowChar;
AllowSeq = allowSeq;
AllowSetVarieties = allowSetVarieties;
+ AllowISet = allowISet;
}
public override int OrderID {
get {
@@ -1451,22 +1531,41 @@ namespace Microsoft.Dafny {
IToken INamedRegion.BodyEndTok { get { return BodyEndTok; } }
string INamedRegion.Name { get { return Name; } }
string compileName;
+ private readonly Declaration clonedFrom;
+
public virtual string CompileName {
get {
if (compileName == null) {
- compileName = NonglobalVariable.CompilerizeName(Name);
+ object externValue = "";
+ string errorMessage = "";
+ bool isExternal = Attributes.ContainsMatchingValue(this.Attributes, "extern", ref externValue,
+ new Attributes.MatchingValueOption[] { Attributes.MatchingValueOption.String },
+ err => errorMessage = err);
+ if (isExternal) {
+ compileName = (string)externValue;
+ }
+ else {
+ compileName = NonglobalVariable.CompilerizeName(Name);
+ }
}
return compileName;
}
}
public Attributes Attributes; // readonly, except during class merging in the refinement transformations
- public Declaration(IToken tok, string name, Attributes attributes) {
+ public Declaration(IToken tok, string name, Attributes attributes, Declaration clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
this.tok = tok;
this.Name = name;
this.Attributes = attributes;
+ this.clonedFrom = clonedFrom;
+ }
+
+ public Declaration ClonedFrom {
+ get {
+ return this.clonedFrom;
+ }
}
[Pure]
@@ -1478,12 +1577,10 @@ namespace Microsoft.Dafny {
internal FreshIdGenerator IdGenerator = new FreshIdGenerator();
}
- public class OpaqueType_AsParameter : TypeParameter
- {
+ public class OpaqueType_AsParameter : TypeParameter {
public readonly List<TypeParameter> TypeArgs;
public OpaqueType_AsParameter(IToken tok, string name, EqualitySupportValue equalitySupport, List<TypeParameter> typeArgs)
- : base(tok, name, equalitySupport)
- {
+ : base(tok, name, equalitySupport) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(typeArgs != null);
@@ -1507,11 +1604,6 @@ namespace Microsoft.Dafny {
set {
Contract.Requires(Parent == null); // set it only once
Contract.Requires(value != null);
- // BUGBUG: The following line is a workaround to tell the verifier that 'value' is not of an Immutable type.
- // A proper solution would be to be able to express that in the program (in a specification or attribute) or
- // to be able to declare 'parent' as [PeerOrImmutable].
- Contract.Requires(value is TopLevelDecl || value is Function || value is Method || value is DatatypeCtor || value is QuantifierExpr);
- //modifies parent;
parent = value;
}
}
@@ -1531,8 +1623,8 @@ namespace Microsoft.Dafny {
}
public int PositionalIndex; // which type parameter this is (ie. in C<S, T, U>, S is 0, T is 1 and U is 2).
- public TypeParameter(IToken tok, string name, EqualitySupportValue equalitySupport = EqualitySupportValue.Unspecified)
- : base(tok, name, null) {
+ public TypeParameter(IToken tok, string name, EqualitySupportValue equalitySupport = EqualitySupportValue.Unspecified, Declaration clonedFrom = null)
+ : base(tok, name, null, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
EqualitySupport = equalitySupport;
@@ -1570,6 +1662,8 @@ namespace Microsoft.Dafny {
public class LiteralModuleDecl : ModuleDecl
{
public readonly ModuleDefinition ModuleDef;
+ public ModuleSignature DefaultExport; // the default export of the module. fill in by the resolver.
+
public LiteralModuleDecl(ModuleDefinition module, ModuleDefinition parent)
: base(module.tok, module.Name, parent, false) {
ModuleDef = module;
@@ -1588,6 +1682,7 @@ namespace Microsoft.Dafny {
}
public override object Dereference() { return Signature.ModuleDef; }
}
+
// Represents "module name as path [ = compilePath];", where name is a identifier and path is a possibly qualified name.
public class ModuleFacadeDecl : ModuleDecl
{
@@ -1606,8 +1701,41 @@ namespace Microsoft.Dafny {
public override object Dereference() { return this; }
}
- public class ModuleSignature {
+ // Represents the exports of a module.
+ public class ModuleExportDecl : ModuleDecl
+ {
+ public bool IsDefault;
+ public List<ExportSignature> Exports; // list of TopLevelDecl that are included in the export
+ public List<string> Extends; // list of exports that are extended
+ public readonly List<ModuleExportDecl> ExtendDecls = new List<ModuleExportDecl>(); // fill in by the resolver
+
+ public ModuleExportDecl(IToken tok, ModuleDefinition parent, bool isDefault,
+ List<ExportSignature> exports, List<string> extends)
+ : base(tok, tok.val, parent, false) {
+ IsDefault = isDefault;
+ Exports = exports;
+ Extends = extends;
+ }
+
+ public override object Dereference() { return this; }
+ }
+ public class ExportSignature
+ {
+ public bool IncludeBody;
+ public IToken Id;
+ public string Name;
+ public Declaration Decl; // fill in by the resolver
+
+ public ExportSignature(IToken id, bool includeBody) {
+ Id = id;
+ Name = id.val;
+ IncludeBody = includeBody;
+ }
+ }
+
+ public class ModuleSignature {
+ private ModuleDefinition exclusiveRefinement = null;
public readonly Dictionary<string, TopLevelDecl> TopLevels = new Dictionary<string, TopLevelDecl>();
public readonly Dictionary<string, Tuple<DatatypeCtor, bool>> Ctors = new Dictionary<string, Tuple<DatatypeCtor, bool>>();
public readonly Dictionary<string, MemberDecl> StaticMembers = new Dictionary<string, MemberDecl>();
@@ -1615,7 +1743,7 @@ namespace Microsoft.Dafny {
// it is abstract). Otherwise, it points to that definition.
public ModuleSignature CompileSignature = null; // This is the version of the signature that should be used at compile time.
public ModuleSignature Refines = null;
- public bool IsGhost = false;
+ public bool IsAbstract = false;
public ModuleSignature() {}
public bool FindSubmodule(string name, out ModuleSignature pp) {
@@ -1628,6 +1756,25 @@ namespace Microsoft.Dafny {
return false;
}
}
+
+ public ModuleDefinition ExclusiveRefinement {
+ get {
+ if (null == exclusiveRefinement) {
+ return ModuleDef == null ? null : ModuleDef.ExclusiveRefinement;
+ } else {
+ return exclusiveRefinement;
+ }
+ }
+
+ set {
+ if (null == ExclusiveRefinement) {
+ exclusiveRefinement = null;
+ } else {
+ throw new InvalidOperationException("An exclusive refinement relationship cannot be amended.");
+ }
+ }
+ }
+
}
public class ModuleDefinition : INamedRegion
@@ -1643,22 +1790,79 @@ namespace Microsoft.Dafny {
public readonly Attributes Attributes;
public readonly List<IToken> RefinementBaseName; // null if no refinement base
public ModuleDecl RefinementBaseRoot; // filled in early during resolution, corresponds to RefinementBaseName[0]
- public ModuleDefinition RefinementBase; // filled in during resolution (null if no refinement base)
+
public List<Include> Includes;
public readonly List<TopLevelDecl> TopLevelDecls = new List<TopLevelDecl>(); // filled in by the parser; readonly after that
public readonly Graph<ICallable> CallGraph = new Graph<ICallable>(); // filled in during resolution
public int Height; // height in the topological sorting of modules; filled in during resolution
public readonly bool IsAbstract;
+ public readonly bool IsExclusiveRefinement;
public readonly bool IsFacade; // True iff this module represents a module facade (that is, an abstract interface)
private readonly bool IsBuiltinName; // true if this is something like _System that shouldn't have it's name mangled.
+
+ private ModuleDefinition exclusiveRefinement;
+
+ public ModuleDefinition ExclusiveRefinement {
+ get { return exclusiveRefinement; }
+ set {
+ if (null == exclusiveRefinement) {
+ if (!value.IsExclusiveRefinement) {
+ throw new ArgumentException(
+ string.Format("Exclusive refinement of {0} with 'new' module {0} is disallowed.",
+ Name,
+ value.Name));
+ }
+ // todo: validate state of `value`.
+ exclusiveRefinement = value;
+ } else {
+ throw new InvalidOperationException(string.Format("Exclusive refinement of {0} has already been established {1}; cannot reestabilish as {2}.", Name, exclusiveRefinement.Name, value.Name));
+ }
+ }
+ }
+
+ public int ExclusiveRefinementCount { get; set; }
+
+ private ModuleSignature refinementBaseSig; // module signature of the refinementBase.
+ public ModuleSignature RefinementBaseSig {
+ get {
+ return refinementBaseSig;
+ }
+
+ set {
+ // the refinementBase member may only be changed once.
+ if (null != refinementBaseSig) {
+ throw new InvalidOperationException(string.Format("This module ({0}) already has a refinement base ({1}).", Name, refinementBase.Name));
+ }
+ refinementBaseSig = value;
+ }
+ }
+
+ private ModuleDefinition refinementBase; // filled in during resolution via RefinementBase property (null if no refinement base yet or at all).
+
+ public ModuleDefinition RefinementBase {
+ get {
+ return refinementBase;
+ }
+
+ set {
+ // the refinementBase member may only be changed once.
+ if (null != refinementBase) {
+ throw new InvalidOperationException(string.Format("This module ({0}) already has a refinement base ({1}).", Name, refinementBase.Name));
+ }
+ refinementBase = value;
+ }
+ }
+
+ public ModuleDefinition ClonedFrom { get; set; }
+
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(cce.NonNullElements(TopLevelDecls));
Contract.Invariant(CallGraph != null);
}
- public ModuleDefinition(IToken tok, string name, bool isAbstract, bool isFacade, List<IToken> refinementBase, ModuleDefinition parent, Attributes attributes, bool isBuiltinName)
+ public ModuleDefinition(IToken tok, string name, bool isAbstract, bool isFacade, bool isExclusiveRefinement, List<IToken> refinementBase, ModuleDefinition parent, Attributes attributes, bool isBuiltinName, Parser parser = null)
{
Contract.Requires(tok != null);
Contract.Requires(name != null);
@@ -1669,10 +1873,19 @@ namespace Microsoft.Dafny {
RefinementBaseName = refinementBase;
IsAbstract = isAbstract;
IsFacade = isFacade;
+ IsExclusiveRefinement = isExclusiveRefinement;
RefinementBaseRoot = null;
- RefinementBase = null;
+ this.refinementBase = null;
Includes = new List<Include>();
IsBuiltinName = isBuiltinName;
+
+ if (isExclusiveRefinement && !DafnyOptions.O.IronDafny) {
+ parser.errors.SynErr(
+ tok.filename,
+ tok.line,
+ tok.col,
+ "The exclusively keyword is experimental and only available when IronDafny features are enabled (/ironDafny).");
+ }
}
public virtual bool IsDefaultModule {
get {
@@ -1683,15 +1896,34 @@ namespace Microsoft.Dafny {
public string CompileName {
get {
if (compileName == null) {
- if (IsBuiltinName)
- compileName = Name;
- else
- compileName = "_" + Height.ToString() + "_" + NonglobalVariable.CompilerizeName(Name);
+ object externValue = "";
+ string errorMessage = "";
+ bool isExternal = Attributes.ContainsMatchingValue(this.Attributes, "extern", ref externValue,
+ new Attributes.MatchingValueOption[] { Attributes.MatchingValueOption.String },
+ err => errorMessage = err);
+ if (isExternal) {
+ compileName = (string)externValue;
+ } else {
+ if (IsBuiltinName)
+ compileName = Name;
+ else
+ compileName = "_" + Height.ToString() + "_" + NonglobalVariable.CompilerizeName(Name);
+ }
}
return compileName;
}
}
+ public string RefinementCompileName {
+ get {
+ if (ExclusiveRefinement != null) {
+ return this.ExclusiveRefinement.RefinementCompileName;
+ } else {
+ return this.CompileName;
+ }
+ }
+ }
+
/// <summary>
/// Determines if "a" and "b" are in the same strongly connected component of the call graph, that is,
/// if "a" and "b" are mutually recursive.
@@ -1809,7 +2041,9 @@ namespace Microsoft.Dafny {
}
public class DefaultModuleDecl : ModuleDefinition {
- public DefaultModuleDecl() : base(Token.NoToken, "_module", false, false, null, null, null, true) {
+ public DefaultModuleDecl()
+ : base(Token.NoToken, "_module", false, false, /*isExclusiveRefinement:*/ false, null, null, null, true)
+ {
}
public override bool IsDefaultModule {
get {
@@ -1827,13 +2061,14 @@ namespace Microsoft.Dafny {
Contract.Invariant(cce.NonNullElements(TypeArgs));
}
- public TopLevelDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs, Attributes attributes)
- : base(tok, name, attributes) {
+ public TopLevelDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs, Attributes attributes, Declaration clonedFrom = null)
+ : base(tok, name, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
Module = module;
TypeArgs = typeArgs;
+ ExclusiveRefinement = null;
}
public string FullName {
@@ -1846,6 +2081,13 @@ namespace Microsoft.Dafny {
return Module.CompileName + "." + CompileName;
}
}
+
+ public string FullSanitizedRefinementName {
+ get {
+ return Module.RefinementCompileName + "." + CompileName;
+ }
+ }
+
public string FullNameInContext(ModuleDefinition context) {
if (Module == context) {
return Name;
@@ -1855,9 +2097,14 @@ namespace Microsoft.Dafny {
}
public string FullCompileName {
get {
- return Module.CompileName + ".@" + CompileName;
+ if (!Module.IsDefaultModule) {
+ return Module.CompileName + ".@" + CompileName;
+ } else {
+ return CompileName;
+ }
}
}
+ public TopLevelDecl ExclusiveRefinement { get; set; }
}
public class TraitDecl : ClassDecl
@@ -1865,8 +2112,8 @@ namespace Microsoft.Dafny {
public override string WhatKind { get { return "trait"; } }
public bool IsParent { set; get; }
public TraitDecl(IToken tok, string name, ModuleDefinition module,
- List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes)
- : base(tok, name, module, typeArgs, members, attributes, null) { }
+ List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes, TraitDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, members, attributes, null, clonedFrom) { }
}
public class ClassDecl : TopLevelDecl {
@@ -1884,8 +2131,8 @@ namespace Microsoft.Dafny {
}
public ClassDecl(IToken tok, string name, ModuleDefinition module,
- List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes, List<Type> traits)
- : base(tok, name, module, typeArgs, attributes) {
+ List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes, List<Type> traits, ClassDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -1899,11 +2146,17 @@ namespace Microsoft.Dafny {
return false;
}
}
+
+ public new ClassDecl ClonedFrom {
+ get {
+ return (ClassDecl)base.ClonedFrom;
+ }
+ }
}
public class DefaultClassDecl : ClassDecl {
- public DefaultClassDecl(ModuleDefinition module, [Captured] List<MemberDecl> members)
- : base(Token.NoToken, "_default", module, new List<TypeParameter>(), members, null, null) {
+ public DefaultClassDecl(ModuleDefinition module, [Captured] List<MemberDecl> members, DefaultClassDecl clonedFrom = null)
+ : base(Token.NoToken, "_default", module, new List<TypeParameter>(), members, null, null, clonedFrom) {
Contract.Requires(module != null);
Contract.Requires(cce.NonNullElements(members));
}
@@ -1936,9 +2189,9 @@ namespace Microsoft.Dafny {
public readonly Function Requires;
public readonly Function Reads;
- public ArrowTypeDecl(List<TypeParameter> tps, Function req, Function reads, ModuleDefinition module, Attributes attributes)
+ public ArrowTypeDecl(List<TypeParameter> tps, Function req, Function reads, ModuleDefinition module, Attributes attributes, ArrowTypeDecl clonedFrom)
: base(Token.NoToken, ArrowType.ArrowTypeName(tps.Count - 1), module, tps,
- new List<MemberDecl> { req, reads }, attributes, null) {
+ new List<MemberDecl> { req, reads }, attributes, null, clonedFrom) {
Contract.Requires(tps != null && 1 <= tps.Count);
Contract.Requires(req != null);
Contract.Requires(reads != null);
@@ -1961,8 +2214,8 @@ namespace Microsoft.Dafny {
}
public DatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,
- [Captured] List<DatatypeCtor> ctors, Attributes attributes)
- : base(tok, name, module, typeArgs, attributes) {
+ [Captured] List<DatatypeCtor> ctors, Attributes attributes, DatatypeDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -1976,6 +2229,12 @@ namespace Microsoft.Dafny {
return (TypeArgs.Count == 0 && Ctors.TrueForAll(ctr => ctr.Formals.Count == 0));
}
}
+
+ public new DatatypeDecl ClonedFrom {
+ get {
+ return (DatatypeDecl)base.ClonedFrom;
+ }
+ }
}
public class IndDatatypeDecl : DatatypeDecl
@@ -1988,8 +2247,8 @@ namespace Microsoft.Dafny {
public ES EqualitySupport = ES.NotYetComputed;
public IndDatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,
- [Captured] List<DatatypeCtor> ctors, Attributes attributes)
- : base(tok, name, module, typeArgs, ctors, attributes) {
+ [Captured] List<DatatypeCtor> ctors, Attributes attributes, IndDatatypeDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, ctors, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -1997,6 +2256,12 @@ namespace Microsoft.Dafny {
Contract.Requires(cce.NonNullElements(ctors));
Contract.Requires(1 <= ctors.Count);
}
+
+ public new IndDatatypeDecl ClonedFrom {
+ get {
+ return (IndDatatypeDecl)base.ClonedFrom;
+ }
+ }
}
public class TupleTypeDecl : IndDatatypeDecl
@@ -2052,8 +2317,8 @@ namespace Microsoft.Dafny {
public CoDatatypeDecl SscRepr; // filled in during resolution
public CoDatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,
- [Captured] List<DatatypeCtor> ctors, Attributes attributes)
- : base(tok, name, module, typeArgs, ctors, attributes) {
+ [Captured] List<DatatypeCtor> ctors, Attributes attributes, CoDatatypeDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, ctors, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -2080,8 +2345,8 @@ namespace Microsoft.Dafny {
public SpecialField QueryField; // filled in during resolution
public List<DatatypeDestructor> Destructors = new List<DatatypeDestructor>(); // contents filled in during resolution; includes both implicit (not mentionable in source) and explicit destructors
- public DatatypeCtor(IToken tok, string name, [Captured] List<Formal> formals, Attributes attributes)
- : base(tok, name, attributes) {
+ public DatatypeCtor(IToken tok, string name, [Captured] List<Formal> formals, Attributes attributes, DatatypeCtor clonedFrom = null)
+ : base(tok, name, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(formals));
@@ -2110,6 +2375,7 @@ namespace Microsoft.Dafny {
bool MustReverify { get; }
string FullSanitizedName { get; }
bool AllowsNontermination { get; }
+ bool ContainsQuantifier { get; set; }
}
/// <summary>
/// An ICallable is a Function, Method, IteratorDecl, or RedirectingTypeDecl.
@@ -2117,6 +2383,7 @@ namespace Microsoft.Dafny {
public interface ICallable : ICodeContext
{
IToken Tok { get; }
+ string WhatKind { get; }
string NameRelativeToModule { get; }
Specification<Expression> Decreases { get; }
/// <summary>
@@ -2126,8 +2393,10 @@ namespace Microsoft.Dafny {
/// </summary>
bool InferredDecreases { get; set; }
}
+
public class DontUseICallable : ICallable
{
+ public string WhatKind { get { throw new cce.UnreachableException(); } }
public bool IsGhost { get { throw new cce.UnreachableException(); } }
public List<TypeParameter> TypeArgs { get { throw new cce.UnreachableException(); } }
public List<Formal> Ins { get { throw new cce.UnreachableException(); } }
@@ -2142,6 +2411,10 @@ namespace Microsoft.Dafny {
get { throw new cce.UnreachableException(); }
set { throw new cce.UnreachableException(); }
}
+ public bool ContainsQuantifier {
+ get { throw new cce.UnreachableException(); }
+ set { throw new cce.UnreachableException(); }
+ }
}
/// <summary>
/// An IMethodCodeContext is a Method or IteratorDecl.
@@ -2170,6 +2443,11 @@ namespace Microsoft.Dafny {
bool ICodeContext.MustReverify { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } }
public string FullSanitizedName { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } }
public bool AllowsNontermination { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } }
+ public bool ContainsQuantifier {
+ get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); }
+ set { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); }
+ }
+
}
public class IteratorDecl : ClassDecl, IMethodCodeContext
@@ -2197,6 +2475,8 @@ namespace Microsoft.Dafny {
public Predicate Member_Valid; // created during registration phase of resolution; its specification is filled in during resolution
public Method Member_MoveNext; // created during registration phase of resolution; its specification is filled in during resolution
public readonly LocalVariable YieldCountVariable;
+ bool containsQuantifier;
+
public IteratorDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,
List<Formal> ins, List<Formal> outs,
Specification<FrameExpression> reads, Specification<FrameExpression> mod, Specification<Expression> decreases,
@@ -2241,6 +2521,48 @@ namespace Microsoft.Dafny {
}
/// <summary>
+ /// Returns the non-null expressions of this declaration proper (that is, do not include the expressions of substatements).
+ /// Does not include the generated class members.
+ /// </summary>
+ public virtual IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var e in Attributes.SubExpressions(Attributes)) {
+ yield return e;
+ }
+ foreach (var e in Attributes.SubExpressions(Reads.Attributes)) {
+ yield return e;
+ }
+ foreach (var e in Reads.Expressions) {
+ yield return e.E;
+ }
+ foreach (var e in Attributes.SubExpressions(Modifies.Attributes)) {
+ yield return e;
+ }
+ foreach (var e in Modifies.Expressions) {
+ yield return e.E;
+ }
+ foreach (var e in Attributes.SubExpressions(Decreases.Attributes)) {
+ yield return e;
+ }
+ foreach (var e in Decreases.Expressions) {
+ yield return e;
+ }
+ foreach (var e in Requires) {
+ yield return e.E;
+ }
+ foreach (var e in Ensures) {
+ yield return e.E;
+ }
+ foreach (var e in YieldRequires) {
+ yield return e.E;
+ }
+ foreach (var e in YieldEnsures) {
+ yield return e.E;
+ }
+ }
+ }
+
+ /// <summary>
/// This Dafny type exists only for the purpose of giving the yield-count variable a type, so
/// that the type can be recognized during translation of Dafny into Boogie. It represents
/// an integer component in a "decreases" clause whose order is (\lambda x,y :: x GREATER y),
@@ -2270,6 +2592,10 @@ namespace Microsoft.Dafny {
set { _inferredDecr = value; }
get { return _inferredDecr; }
}
+ bool ICodeContext.ContainsQuantifier {
+ set { containsQuantifier = value; }
+ get { return containsQuantifier; }
+ }
ModuleDefinition ICodeContext.EnclosingModule { get { return this.Module; } }
bool ICodeContext.MustReverify { get { return false; } }
public bool AllowsNontermination {
@@ -2290,8 +2616,8 @@ namespace Microsoft.Dafny {
public readonly bool IsGhost;
public TopLevelDecl EnclosingClass; // filled in during resolution
public MemberDecl RefinementBase; // filled in during the pre-resolution refinement transformation; null if the member is new here
- public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes)
- : base(tok, name, attributes) {
+ public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes, Declaration clonedFrom = null)
+ : base(tok, name, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
HasStaticKeyword = hasStaticKeyword;
@@ -2316,6 +2642,14 @@ namespace Microsoft.Dafny {
return EnclosingClass.FullSanitizedName + "." + CompileName;
}
}
+ public string FullSanitizedRefinementName {
+ get {
+ Contract.Requires(EnclosingClass != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ return EnclosingClass.FullSanitizedRefinementName + "." + CompileName;
+ }
+ }
public string FullNameInContext(ModuleDefinition context) {
Contract.Requires(EnclosingClass != null);
Contract.Ensures(Contract.Result<string>() != null);
@@ -2339,6 +2673,11 @@ namespace Microsoft.Dafny {
return EnclosingClass.FullCompileName + ".@" + CompileName;
}
}
+ public virtual IEnumerable<Expression> SubExpressions {
+ get {
+ yield break;
+ }
+ }
}
public class Field : MemberDecl {
@@ -2428,8 +2767,8 @@ namespace Microsoft.Dafny {
Contract.Invariant(TheType != null && Name == TheType.Name);
}
- public OpaqueTypeDecl(IToken tok, string name, ModuleDefinition module, TypeParameter.EqualitySupportValue equalitySupport, List<TypeParameter> typeArgs, Attributes attributes)
- : base(tok, name, module, typeArgs, attributes) {
+ public OpaqueTypeDecl(IToken tok, string name, ModuleDefinition module, TypeParameter.EqualitySupportValue equalitySupport, List<TypeParameter> typeArgs, Attributes attributes, Declaration clonedFrom = null)
+ : base(tok, name, module, typeArgs, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -2470,16 +2809,16 @@ namespace Microsoft.Dafny {
public readonly BoundVar Var; // can be null (if non-null, then object.ReferenceEquals(Var.Type, BaseType))
public readonly Expression Constraint; // is null iff Var is
public NativeType NativeType; // non-null for fixed-size representations (otherwise, use BigIntegers for integers)
- public NewtypeDecl(IToken tok, string name, ModuleDefinition module, Type baseType, Attributes attributes)
- : base(tok, name, module, new List<TypeParameter>(), attributes) {
+ public NewtypeDecl(IToken tok, string name, ModuleDefinition module, Type baseType, Attributes attributes, NewtypeDecl clonedFrom = null)
+ : base(tok, name, module, new List<TypeParameter>(), attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
Contract.Requires(baseType != null);
BaseType = baseType;
}
- public NewtypeDecl(IToken tok, string name, ModuleDefinition module, BoundVar bv, Expression constraint, Attributes attributes)
- : base(tok, name, module, new List<TypeParameter>(), attributes) {
+ public NewtypeDecl(IToken tok, string name, ModuleDefinition module, BoundVar bv, Expression constraint, Attributes attributes, NewtypeDecl clonedFrom = null)
+ : base(tok, name, module, new List<TypeParameter>(), attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -2510,14 +2849,23 @@ namespace Microsoft.Dafny {
get { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases
set { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases
}
+ bool ICodeContext.ContainsQuantifier {
+ get { throw new cce.UnreachableException(); }
+ set { throw new cce.UnreachableException(); }
+ }
+ public new NewtypeDecl ClonedFrom {
+ get {
+ return (NewtypeDecl)base.ClonedFrom;
+ }
+ }
}
public class TypeSynonymDecl : TopLevelDecl, RedirectingTypeDecl
{
public override string WhatKind { get { return "type synonym"; } }
public readonly Type Rhs;
- public TypeSynonymDecl(IToken tok, string name, List<TypeParameter> typeArgs, ModuleDefinition module, Type rhs, Attributes attributes)
- : base(tok, name, module, typeArgs, attributes) {
+ public TypeSynonymDecl(IToken tok, string name, List<TypeParameter> typeArgs, ModuleDefinition module, Type rhs, Attributes attributes, TypeSynonymDecl clonedFrom = null)
+ : base(tok, name, module, typeArgs, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(typeArgs != null);
@@ -2562,6 +2910,10 @@ namespace Microsoft.Dafny {
get { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases
set { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases
}
+ bool ICodeContext.ContainsQuantifier {
+ get { throw new cce.UnreachableException(); }
+ set { throw new cce.UnreachableException(); }
+ }
}
[ContractClass(typeof(IVariableContracts))]
@@ -2823,19 +3175,7 @@ namespace Microsoft.Dafny {
}
}
- /// <summary>
- /// A "ThisSurrogate" is used during translation time to make the treatment of the receiver more similar to
- /// the treatment of other in-parameters.
- /// </summary>
- public class ThisSurrogate : Formal
- {
- public ThisSurrogate(IToken tok, Type type)
- : base(tok, "this", type, true, false) {
- Contract.Requires(tok != null);
- Contract.Requires(type != null);
- }
- }
-
+ [DebuggerDisplay("Bound<{name}>")]
public class BoundVar : NonglobalVariable {
public override bool IsMutable {
get {
@@ -2855,6 +3195,7 @@ namespace Microsoft.Dafny {
public override string WhatKind { get { return "function"; } }
public readonly bool IsProtected;
public bool IsRecursive; // filled in during resolution
+ public bool IsFueled; // filled in during resolution if anyone tries to adjust this function's fuel
public readonly List<TypeParameter> TypeArgs;
public readonly List<Formal> Formals;
public readonly Type ResultType;
@@ -2867,6 +3208,31 @@ namespace Microsoft.Dafny {
public readonly IToken SignatureEllipsis;
public bool IsBuiltin;
public Function OverriddenFunction;
+ public bool containsQuantifier;
+ public bool ContainsQuantifier {
+ set { containsQuantifier = value; }
+ get { return containsQuantifier; }
+ }
+
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var e in Req) {
+ yield return e;
+ }
+ foreach (var e in Reads) {
+ yield return e.E;
+ }
+ foreach (var e in Ens) {
+ yield return e;
+ }
+ foreach (var e in Decreases.Expressions) {
+ yield return e;
+ }
+ if (Body != null) {
+ yield return Body;
+ }
+ }
+ }
public Type Type {
get {
@@ -2880,7 +3246,7 @@ namespace Microsoft.Dafny {
return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr);
}
}
-
+
/// <summary>
/// The "AllCalls" field is used for non-FixpointPredicate, non-PrefixPredicate functions only (so its value should not be relied upon for FixpointPredicate and PrefixPredicate functions).
/// It records all function calls made by the Function, including calls made in the body as well as in the specification.
@@ -2912,8 +3278,8 @@ namespace Microsoft.Dafny {
public Function(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost,
List<TypeParameter> typeArgs, List<Formal> formals, Type resultType,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
- Expression body, Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, isGhost, attributes) {
+ Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
@@ -2925,6 +3291,7 @@ namespace Microsoft.Dafny {
Contract.Requires(cce.NonNullElements(ens));
Contract.Requires(decreases != null);
this.IsProtected = isProtected;
+ this.IsFueled = false; // Defaults to false. Only set to true if someone mentions this function in a fuel annotation
this.TypeArgs = typeArgs;
this.Formals = formals;
this.ResultType = resultType;
@@ -2934,7 +3301,27 @@ namespace Microsoft.Dafny {
this.Decreases = decreases;
this.Body = body;
this.SignatureEllipsis = signatureEllipsis;
+
+ if (attributes != null) {
+ List<Expression> args = Attributes.FindExpressions(attributes, "fuel");
+ if (args != null) {
+ if (args.Count == 1) {
+ LiteralExpr literal = args[0] as LiteralExpr;
+ if (literal != null && literal.Value is BigInteger) {
+ this.IsFueled = true;
+ }
+ } else if (args.Count == 2) {
+ LiteralExpr literalLow = args[0] as LiteralExpr;
+ LiteralExpr literalHigh = args[1] as LiteralExpr;
+
+ if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) {
+ this.IsFueled = true;
+ }
+ }
+ }
+ }
}
+
bool ICodeContext.IsGhost { get { return this.IsGhost; } }
List<TypeParameter> ICodeContext.TypeArgs { get { return this.TypeArgs; } }
@@ -2949,6 +3336,9 @@ namespace Microsoft.Dafny {
}
ModuleDefinition ICodeContext.EnclosingModule { get { return this.EnclosingClass.Module; } }
bool ICodeContext.MustReverify { get { return false; } }
+
+ [Pure]
+ public bool IsFuelAware() { return IsRecursive || IsFueled; }
}
public class Predicate : Function
@@ -2964,8 +3354,8 @@ namespace Microsoft.Dafny {
public Predicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost,
List<TypeParameter> typeArgs, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
- Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureEllipsis) {
+ Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
Contract.Requires(bodyOrigin == Predicate.BodyOriginKind.OriginalOrInherited || body != null);
BodyOrigin = bodyOrigin;
}
@@ -2983,7 +3373,7 @@ namespace Microsoft.Dafny {
List<TypeParameter> typeArgs, Formal k, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
Expression body, Attributes attributes, FixpointPredicate fixpointPred)
- : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, null) {
+ : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, null, null) {
Contract.Requires(k != null);
Contract.Requires(fixpointPred != null);
Contract.Requires(formals != null && 1 <= formals.Count && formals[0] == k);
@@ -3000,9 +3390,9 @@ namespace Microsoft.Dafny {
public FixpointPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected,
List<TypeParameter> typeArgs, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens,
- Expression body, Attributes attributes, IToken signatureEllipsis)
+ Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
: base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(),
- req, reads, ens, new Specification<Expression>(new List<Expression>(), null), body, attributes, signatureEllipsis) {
+ req, reads, ens, new Specification<Expression>(new List<Expression>(), null), body, attributes, signatureEllipsis, clonedFrom) {
}
/// <summary>
@@ -3023,7 +3413,7 @@ namespace Microsoft.Dafny {
prefixPredCall.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();
var old_to_new = new Dictionary<TypeParameter, TypeParameter>();
for (int i = 0; i < this.TypeArgs.Count; i++) {
- old_to_new[this.TypeArgs[i]] = this.PrefixPredicate.TypeArgs[i];
+ old_to_new[this.TypeArgs[i]] = this.PrefixPredicate.TypeArgs[i];
}
foreach (var p in fexp.TypeArgumentSubstitutions) {
prefixPredCall.TypeArgumentSubstitutions[old_to_new[p.Key]] = p.Value;
@@ -3041,9 +3431,9 @@ namespace Microsoft.Dafny {
public InductivePredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected,
List<TypeParameter> typeArgs, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens,
- Expression body, Attributes attributes, IToken signatureEllipsis)
+ Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
: base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals,
- req, reads, ens, body, attributes, signatureEllipsis) {
+ req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) {
}
}
@@ -3053,9 +3443,9 @@ namespace Microsoft.Dafny {
public CoPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected,
List<TypeParameter> typeArgs, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens,
- Expression body, Attributes attributes, IToken signatureEllipsis)
+ Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
: base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals,
- req, reads, ens, body, attributes, signatureEllipsis) {
+ req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) {
}
}
@@ -3077,6 +3467,25 @@ namespace Microsoft.Dafny {
public bool IsTailRecursive; // filled in during resolution
public readonly ISet<IVariable> AssignedAssumptionVariables = new HashSet<IVariable>();
public Method OverriddenMethod;
+ public bool containsQuantifier;
+
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var e in Req) {
+ yield return e.E;
+ }
+ foreach (var e in Mod.Expressions) {
+ yield return e.E;
+ }
+ foreach (var e in Ens) {
+ yield return e.E;
+ }
+ foreach (var e in Decreases.Expressions) {
+ yield return e;
+ }
+ }
+ }
+
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -3097,8 +3506,8 @@ namespace Microsoft.Dafny {
[Captured] List<MaybeFreeExpression> ens,
[Captured] Specification<Expression> decreases,
[Captured] BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, isGhost, attributes) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -3133,6 +3542,11 @@ namespace Microsoft.Dafny {
set { _inferredDecr = value; }
get { return _inferredDecr; }
}
+ bool ICodeContext.ContainsQuantifier {
+ set { containsQuantifier = value; }
+ get { return containsQuantifier; }
+ }
+
ModuleDefinition ICodeContext.EnclosingModule {
get {
Contract.Assert(this.EnclosingClass != null); // this getter is supposed to be called only after signature-resolution is complete
@@ -3170,8 +3584,8 @@ namespace Microsoft.Dafny {
[Captured] List<MaybeFreeExpression> ens,
[Captured] Specification<Expression> decreases,
[Captured] BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
}
}
@@ -3185,8 +3599,8 @@ namespace Microsoft.Dafny {
[Captured] List<MaybeFreeExpression> ens,
[Captured] Specification<Expression> decreases,
[Captured] BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, body, attributes, signatureEllipsis) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -3237,8 +3651,8 @@ namespace Microsoft.Dafny {
List<MaybeFreeExpression> ens,
Specification<Expression> decreases,
BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom)
+ : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -3263,8 +3677,8 @@ namespace Microsoft.Dafny {
List<MaybeFreeExpression> ens,
Specification<Expression> decreases,
BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -3289,8 +3703,8 @@ namespace Microsoft.Dafny {
List<MaybeFreeExpression> ens,
Specification<Expression> decreases,
BlockStmt body,
- Attributes attributes, IToken signatureEllipsis)
- : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {
+ Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null)
+ : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
Contract.Requires(cce.NonNullElements(typeArgs));
@@ -3614,7 +4028,7 @@ namespace Microsoft.Dafny {
Contract.Invariant(Expr != null);
}
- public ExprRhs(Expression expr, Attributes attrs = null)
+ public ExprRhs(Expression expr, Attributes attrs = null) // TODO: these 'attrs' apparently aren't handled correctly in the Cloner, and perhaps not in various visitors either (for example, CheckIsCompilable should not go into attributes)
: base(expr.tok, attrs)
{
Contract.Requires(expr != null);
@@ -3775,6 +4189,28 @@ namespace Microsoft.Dafny {
}
}
+ public class LetStmt : Statement
+ {
+ public readonly List<CasePattern> LHSs;
+ public readonly List<Expression> RHSs;
+
+ public LetStmt(IToken tok, IToken endTok, List<CasePattern> lhss, List<Expression> rhss)
+ : base(tok, endTok) {
+ LHSs = lhss;
+ RHSs = rhss;
+ }
+
+ public IEnumerable<BoundVar> BoundVars {
+ get {
+ foreach (var lhs in LHSs) {
+ foreach (var bv in lhs.Vars) {
+ yield return bv;
+ }
+ }
+ }
+ }
+ }
+
/// <summary>
/// Common superclass of UpdateStmt and AssignSuchThatStmt.
/// </summary>
@@ -3804,6 +4240,9 @@ namespace Microsoft.Dafny {
public override bool IsFinite {
get { return false; }
}
+ public override int Preference() {
+ return 0;
+ }
}
/// <summary>
@@ -3914,17 +4353,41 @@ namespace Microsoft.Dafny {
/// </summary>
public static bool LhsIsToGhost(Expression lhs) {
Contract.Requires(lhs != null);
+ return LhsIsToGhost_Which(lhs) == NonGhostKind.IsGhost;
+ }
+ public enum NonGhostKind { IsGhost, Variable, Field, ArrayElement }
+ public static string NonGhostKind_To_String(NonGhostKind gk) {
+ Contract.Requires(gk != NonGhostKind.IsGhost);
+ switch (gk) {
+ case NonGhostKind.Variable: return "non-ghost variable";
+ case NonGhostKind.Field: return "non-ghost field";
+ case NonGhostKind.ArrayElement: return "array element";
+ default:
+ Contract.Assume(false); // unexpected NonGhostKind
+ throw new cce.UnreachableException(); // please compiler
+ }
+ }
+ /// <summary>
+ /// This method assumes "lhs" has been successfully resolved.
+ /// </summary>
+ public static NonGhostKind LhsIsToGhost_Which(Expression lhs) {
+ Contract.Requires(lhs != null);
lhs = lhs.Resolved;
if (lhs is IdentifierExpr) {
var x = (IdentifierExpr)lhs;
- return x.Var.IsGhost;
+ if (!x.Var.IsGhost) {
+ return NonGhostKind.Variable;
+ }
} else if (lhs is MemberSelectExpr) {
var x = (MemberSelectExpr)lhs;
- return x.Member.IsGhost;
+ if (!x.Member.IsGhost) {
+ return NonGhostKind.Field;
+ }
} else {
// LHS denotes an array element, which is always non-ghost
- return false;
+ return NonGhostKind.ArrayElement;
}
+ return NonGhostKind.IsGhost;
}
}
@@ -4095,20 +4558,24 @@ namespace Microsoft.Dafny {
}
public class IfStmt : Statement {
+ public readonly bool IsExistentialGuard;
public readonly Expression Guard;
public readonly BlockStmt Thn;
public readonly Statement Els;
[ContractInvariantMethod]
void ObjectInvariant() {
+ Contract.Invariant(!IsExistentialGuard || (Guard is ExistsExpr && ((ExistsExpr)Guard).Range == null));
Contract.Invariant(Thn != null);
Contract.Invariant(Els == null || Els is BlockStmt || Els is IfStmt || Els is SkeletonStatement);
}
- public IfStmt(IToken tok, IToken endTok, Expression guard, BlockStmt thn, Statement els)
+ public IfStmt(IToken tok, IToken endTok, bool isExistentialGuard, Expression guard, BlockStmt thn, Statement els)
: base(tok, endTok) {
Contract.Requires(tok != null);
Contract.Requires(endTok != null);
+ Contract.Requires(!isExistentialGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));
Contract.Requires(thn != null);
Contract.Requires(els == null || els is BlockStmt || els is IfStmt || els is SkeletonStatement);
+ this.IsExistentialGuard = isExistentialGuard;
this.Guard = guard;
this.Thn = thn;
this.Els = els;
@@ -4134,20 +4601,24 @@ namespace Microsoft.Dafny {
public class GuardedAlternative
{
public readonly IToken Tok;
+ public readonly bool IsExistentialGuard;
public readonly Expression Guard;
public readonly List<Statement> Body;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Tok != null);
Contract.Invariant(Guard != null);
+ Contract.Invariant(!IsExistentialGuard || (Guard is ExistsExpr && ((ExistsExpr)Guard).Range == null));
Contract.Invariant(Body != null);
}
- public GuardedAlternative(IToken tok, Expression guard, List<Statement> body)
+ public GuardedAlternative(IToken tok, bool isExistentialGuard, Expression guard, List<Statement> body)
{
Contract.Requires(tok != null);
Contract.Requires(guard != null);
+ Contract.Requires(!isExistentialGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));
Contract.Requires(body != null);
this.Tok = tok;
+ this.IsExistentialGuard = isExistentialGuard;
this.Guard = guard;
this.Body = body;
}
@@ -4327,6 +4798,7 @@ namespace Microsoft.Dafny {
public readonly Expression Range;
public readonly List<MaybeFreeExpression> Ens;
public readonly Statement Body;
+ public List<Expression> ForallExpressions; // fill in by rewriter.
public List<ComprehensionExpr.BoundedPool> Bounds; // initialized and filled in by resolver
// invariant: if successfully resolved, Bounds.Count == BoundVars.Count;
@@ -4541,7 +5013,12 @@ namespace Microsoft.Dafny {
public override Expression StepExpr(Expression line0, Expression line1)
{
- return new BinaryExpr(line0.tok, Op, line0, line1);
+ if (Op == BinaryExpr.Opcode.Exp) {
+ // The order of operands is reversed so that it can be turned into implication during resolution
+ return new BinaryExpr(line0.tok, Op, line1, line0);
+ } else {
+ return new BinaryExpr(line0.tok, Op, line0, line1);
+ }
}
public override string ToString()
@@ -4621,7 +5098,7 @@ namespace Microsoft.Dafny {
Contract.Invariant(StepOps.Count == Hints.Count);
}
- public CalcStmt(IToken tok, IToken endTok, CalcOp op, List<Expression> lines, List<BlockStmt> hints, List<CalcOp> stepOps, CalcOp resultOp)
+ public CalcStmt(IToken tok, IToken endTok, CalcOp op, List<Expression> lines, List<BlockStmt> hints, List<CalcOp> stepOps, CalcOp resultOp, Attributes attrs)
: base(tok, endTok)
{
Contract.Requires(tok != null);
@@ -4646,6 +5123,7 @@ namespace Microsoft.Dafny {
}
this.Steps = new List<Expression>();
this.Result = null;
+ this.Attributes = attrs;
}
public override IEnumerable<Statement> SubStatements
@@ -4660,14 +5138,30 @@ namespace Microsoft.Dafny {
{
get {
foreach (var e in base.SubExpressions) { yield return e; }
- foreach (var l in Lines) {
- yield return l;
+ foreach (var e in Attributes.SubExpressions(Attributes)) { yield return e; }
+
+ for (int i = 0; i < Lines.Count - 1; i++) { // note, we skip the duplicated line at the end
+ yield return Lines[i];
}
- foreach (var e in Steps) {
- yield return e;
+ foreach (var calcop in AllCalcOps) {
+ var o3 = calcop as TernaryCalcOp;
+ if (o3 != null) {
+ yield return o3.Index;
+ }
}
- if (Result != null) {
- yield return Result;
+ }
+ }
+
+ IEnumerable<CalcOp> AllCalcOps {
+ get {
+ if (Op != null) {
+ yield return Op;
+ }
+ foreach (var stepop in StepOps) {
+ yield return stepop;
+ }
+ if (ResultOp != null) {
+ yield return ResultOp;
}
}
}
@@ -4710,8 +5204,8 @@ namespace Microsoft.Dafny {
Contract.Invariant(cce.NonNullElements(MissingCases));
}
- public readonly Expression Source;
- public readonly List<MatchCaseStmt> Cases;
+ private Expression source;
+ private List<MatchCaseStmt> cases;
public readonly List<DatatypeCtor> MissingCases = new List<DatatypeCtor>(); // filled in during resolution
public readonly bool UsesOptionalBraces;
@@ -4721,14 +5215,31 @@ namespace Microsoft.Dafny {
Contract.Requires(endTok != null);
Contract.Requires(source != null);
Contract.Requires(cce.NonNullElements(cases));
- this.Source = source;
- this.Cases = cases;
+ this.source = source;
+ this.cases = cases;
this.UsesOptionalBraces = usesOptionalBraces;
}
+ public Expression Source {
+ get { return source; }
+ }
+
+ public List<MatchCaseStmt> Cases {
+ get { return cases; }
+ }
+
+ // should only be used in desugar in resolve to change the cases of the matchexpr
+ public void UpdateSource(Expression source) {
+ this.source = source;
+ }
+
+ public void UpdateCases(List<MatchCaseStmt> cases) {
+ this.cases = cases;
+ }
+
public override IEnumerable<Statement> SubStatements {
get {
- foreach (var kase in Cases) {
+ foreach (var kase in cases) {
foreach (var s in kase.Body) {
yield return s;
}
@@ -4745,7 +5256,7 @@ namespace Microsoft.Dafny {
public class MatchCaseStmt : MatchCase
{
- public readonly List<Statement> Body;
+ private List<Statement> body;
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -4759,7 +5270,25 @@ namespace Microsoft.Dafny {
Contract.Requires(id != null);
Contract.Requires(cce.NonNullElements(arguments));
Contract.Requires(cce.NonNullElements(body));
- this.Body = body;
+ this.body = body;
+ }
+
+ public MatchCaseStmt(IToken tok, string id, [Captured] List<CasePattern> cps, [Captured] List<Statement> body)
+ : base(tok, id, cps) {
+ Contract.Requires(tok != null);
+ Contract.Requires(id != null);
+ Contract.Requires(cce.NonNullElements(cps));
+ Contract.Requires(cce.NonNullElements(body));
+ this.body = body;
+ }
+
+ public List<Statement> Body {
+ get { return body; }
+ }
+
+ // should only be called by resolve to reset the body of the MatchCaseExpr
+ public void UpdateBody(List<Statement> body) {
+ this.body = body;
}
}
@@ -4896,7 +5425,7 @@ namespace Microsoft.Dafny {
}
// ------------------------------------------------------------------------------------------------------
-
+ [DebuggerDisplay("{Printer.ExprToString(this)}")]
public abstract class Expression
{
public readonly IToken tok;
@@ -4961,6 +5490,10 @@ namespace Microsoft.Dafny {
get { yield break; }
}
+ public virtual bool IsImplicit {
+ get { return false; }
+ }
+
public static IEnumerable<Expression> Conjuncts(Expression expr) {
Contract.Requires(expr != null);
Contract.Requires(expr.Type.IsBoolType);
@@ -4995,7 +5528,9 @@ namespace Microsoft.Dafny {
public static Expression CreateAdd(Expression e0, Expression e1) {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
- Contract.Requires((e0.Type.IsIntegerType && e1.Type.IsIntegerType) || (e0.Type.IsRealType && e1.Type.IsRealType));
+ Contract.Requires(
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));
Contract.Ensures(Contract.Result<Expression>() != null);
var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Add, e0, e1);
s.ResolvedOp = BinaryExpr.ResolvedOpcode.Add; // resolve here
@@ -5003,6 +5538,7 @@ namespace Microsoft.Dafny {
return s;
}
+
/// <summary>
/// Create a resolved expression of the form "CVT(e0) - CVT(e1)", where "CVT" is either "int" (if
/// e0.Type is an integer-based numeric type) or "real" (if e0.Type is a real-based numeric type).
@@ -5016,20 +5552,32 @@ namespace Microsoft.Dafny {
Contract.Ensures(Contract.Result<Expression>() != null);
Type toType = e0.Type.IsNumericBased(Type.NumericPersuation.Int) ? (Type)Type.Int : Type.Real;
- e0 = new ConversionExpr(e0.tok, e0, toType);
- e0.Type = toType;
- e1 = new ConversionExpr(e1.tok, e1, toType);
- e1.Type = toType;
+ e0 = CastIfNeeded(e0, toType);
+ e1 = CastIfNeeded(e1, toType);
return CreateSubtract(e0, e1);
}
+ private static Expression CastIfNeeded(Expression expr, Type toType) {
+ if (!expr.Type.Equals(toType)) {
+ var cast = new ConversionExpr(expr.tok, expr, toType);
+ cast.Type = toType;
+ return cast;
+ } else {
+ return expr;
+ }
+ }
+
/// <summary>
/// Create a resolved expression of the form "e0 - e1"
/// </summary>
public static Expression CreateSubtract(Expression e0, Expression e1) {
Contract.Requires(e0 != null);
+ Contract.Requires(e0.Type != null);
Contract.Requires(e1 != null);
- Contract.Requires((e0.Type.IsIntegerType && e1.Type.IsIntegerType) || (e0.Type.IsRealType && e1.Type.IsRealType));
+ Contract.Requires(e1.Type != null);
+ Contract.Requires(
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));
Contract.Ensures(Contract.Result<Expression>() != null);
var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Sub, e0, e1);
s.ResolvedOp = BinaryExpr.ResolvedOpcode.Sub; // resolve here
@@ -5042,7 +5590,8 @@ namespace Microsoft.Dafny {
/// </summary>
public static Expression CreateIncrement(Expression e, int n) {
Contract.Requires(e != null);
- Contract.Requires(e.Type.IsIntegerType);
+ Contract.Requires(e.Type != null);
+ Contract.Requires(e.Type.IsNumericBased(Type.NumericPersuation.Int));
Contract.Requires(0 <= n);
Contract.Ensures(Contract.Result<Expression>() != null);
if (n == 0) {
@@ -5057,7 +5606,7 @@ namespace Microsoft.Dafny {
/// </summary>
public static Expression CreateDecrement(Expression e, int n) {
Contract.Requires(e != null);
- Contract.Requires(e.Type.IsIntegerType);
+ Contract.Requires(e.Type.IsNumericBased(Type.NumericPersuation.Int));
Contract.Requires(0 <= n);
Contract.Ensures(Contract.Result<Expression>() != null);
if (n == 0) {
@@ -5116,7 +5665,7 @@ namespace Microsoft.Dafny {
public static Expression CreateLess(Expression e0, Expression e1) {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
- Contract.Requires(e0.Type.IsIntegerType && e1.Type.IsIntegerType);
+ Contract.Requires(e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int));
Contract.Ensures(Contract.Result<Expression>() != null);
var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Lt, e0, e1);
s.ResolvedOp = BinaryExpr.ResolvedOpcode.Lt; // resolve here
@@ -5130,7 +5679,9 @@ namespace Microsoft.Dafny {
public static Expression CreateAtMost(Expression e0, Expression e1) {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
- Contract.Requires((e0.Type.IsIntegerType && e1.Type.IsIntegerType) || (e0.Type.IsRealType && e1.Type.IsRealType));
+ Contract.Requires(
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||
+ (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));
Contract.Ensures(Contract.Result<Expression>() != null);
var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Le, e0, e1);
s.ResolvedOp = BinaryExpr.ResolvedOpcode.Le; // resolve here
@@ -5337,19 +5888,21 @@ namespace Microsoft.Dafny {
public class StaticReceiverExpr : LiteralExpr
{
public readonly Type UnresolvedType;
+ private bool Implicit;
- public StaticReceiverExpr(IToken tok, Type t)
+ public StaticReceiverExpr(IToken tok, Type t, bool isImplicit)
: base(tok) {
Contract.Requires(tok != null);
Contract.Requires(t != null);
UnresolvedType = t;
+ Implicit = isImplicit;
}
/// <summary>
/// Constructs a resolved LiteralExpr representing the 'null' literal whose type is "cl"
/// parameterized by the type arguments of "cl" itself.
/// </summary>
- public StaticReceiverExpr(IToken tok, ClassDecl cl)
+ public StaticReceiverExpr(IToken tok, ClassDecl cl, bool isImplicit)
: base(tok)
{
Contract.Requires(tok != null);
@@ -5357,6 +5910,7 @@ namespace Microsoft.Dafny {
var typeArgs = cl.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp));
Type = new UserDefinedType(tok, cl.Name, cl, typeArgs);
UnresolvedType = Type;
+ Implicit = isImplicit;
}
/// <summary>
@@ -5373,7 +5927,7 @@ namespace Microsoft.Dafny {
/// a trait that in turn extends trait "W(g(Y))". If "t" denotes type "C(G)" and "cl" denotes "W",
/// then type of the StaticReceiverExpr will be "T(g(f(G)))".
/// </summary>
- public StaticReceiverExpr(IToken tok, UserDefinedType t, ClassDecl cl)
+ public StaticReceiverExpr(IToken tok, UserDefinedType t, ClassDecl cl, bool isImplicit)
: base(tok) {
Contract.Requires(tok != null);
Contract.Requires(t.ResolvedClass != null);
@@ -5387,6 +5941,11 @@ namespace Microsoft.Dafny {
}
Type = t;
UnresolvedType = Type;
+ Implicit = isImplicit;
+ }
+
+ public override bool IsImplicit {
+ get { return Implicit; }
}
}
@@ -5502,8 +6061,8 @@ namespace Microsoft.Dafny {
Contract.Invariant(cce.NonNullElements(Arguments));
Contract.Invariant(cce.NonNullElements(InferredTypeArgs));
Contract.Invariant(
- Ctor == null ||
- InferredTypeArgs.Count == Ctor.EnclosingDatatype.TypeArgs.Count);
+ Ctor == null ||
+ InferredTypeArgs.Count == Ctor.EnclosingDatatype.TypeArgs.Count);
}
public DatatypeValue(IToken tok, string datatypeName, string memberName, [Captured] List<Expression> arguments)
@@ -5543,6 +6102,10 @@ namespace Microsoft.Dafny {
: base(tok) {
Contract.Requires(tok != null);
}
+
+ public override bool IsImplicit {
+ get { return true; }
+ }
}
public class IdentifierExpr : Expression
@@ -5561,6 +6124,16 @@ namespace Microsoft.Dafny {
Contract.Requires(name != null);
Name = name;
}
+ /// <summary>
+ /// Constructs a resolved IdentifierExpr.
+ /// </summary>
+ public IdentifierExpr(IVariable v)
+ : base(v.Tok) {
+ Contract.Requires(v != null);
+ Name = v.Name;
+ Var = v;
+ Type = v.Type;
+ }
}
/// <summary>
@@ -5656,10 +6229,12 @@ namespace Microsoft.Dafny {
}
public class SetDisplayExpr : DisplayExpression {
- public SetDisplayExpr(IToken tok, List<Expression> elements)
+ public bool Finite;
+ public SetDisplayExpr(IToken tok, bool finite, List<Expression> elements)
: base(tok, elements) {
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(elements));
+ Finite = finite;
}
}
@@ -5762,7 +6337,6 @@ namespace Microsoft.Dafny {
}
}
-
public override IEnumerable<Expression> SubExpressions {
get { yield return Obj; }
}
@@ -5931,10 +6505,10 @@ namespace Microsoft.Dafny {
Function == null || TypeArgumentSubstitutions == null ||
Contract.ForAll(
Function.TypeArgs,
- a => TypeArgumentSubstitutions.ContainsKey(a)) &&
+ a => TypeArgumentSubstitutions.ContainsKey(a)) &&
Contract.ForAll(
TypeArgumentSubstitutions.Keys,
- a => Function.TypeArgs.Contains(a) || Function.EnclosingClass.TypeArgs.Contains(a)));
+ a => Function.TypeArgs.Contains(a) || Function.EnclosingClass.TypeArgs.Contains(a)));
}
public Function Function; // filled in by resolution
@@ -6338,14 +6912,17 @@ namespace Microsoft.Dafny {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
this.Op = op;
- if (op == Opcode.Exp) {
- // The order of operands is reversed so that it can be turned into implication during resolution
- this.E0 = e1;
- this.E1 = e0;
- } else {
- this.E0 = e0;
- this.E1 = e1;
- }
+ this.E0 = e0;
+ this.E1 = e1;
+ }
+
+ /// <summary>
+ /// Returns a resolved binary expression
+ /// </summary>
+ public BinaryExpr(Boogie.IToken tok, BinaryExpr.ResolvedOpcode rop, Expression e0, Expression e1)
+ : this(tok, BinaryExpr.ResolvedOp2SyntacticOp(rop), e0, e1) {
+ ResolvedOp = rop;
+ Type = Type.Bool;
}
public override IEnumerable<Expression> SubExpressions {
@@ -6391,7 +6968,7 @@ namespace Microsoft.Dafny {
public readonly Expression Body;
public readonly bool Exact; // Exact==true means a regular let expression; Exact==false means an assign-such-that expression
public readonly Attributes Attributes;
- public List<ComprehensionExpr.BoundedPool> Constraint_Bounds; // initialized and filled in by resolver; null for Exact=true and for a ghost statement
+ public List<ComprehensionExpr.BoundedPool> Constraint_Bounds; // initialized and filled in by resolver; null for Exact=true and for when expression is in a ghost context
// invariant Constraint_Bounds == null || Constraint_Bounds.Count == BoundVars.Count;
public List<IVariable> Constraint_MissingBounds; // filled in during resolution; remains "null" if Exact==true or if bounds can be found
// invariant Constraint_Bounds == null || Constraint_MissingBounds == null;
@@ -6478,15 +7055,87 @@ namespace Microsoft.Dafny {
Contract.Invariant(Term != null);
}
- public readonly Attributes Attributes;
+ public Attributes Attributes;
public abstract class BoundedPool {
public virtual bool IsFinite {
get { return true; } // most bounds are finite
}
+ public abstract int Preference(); // higher is better
+
+ public static BoundedPool GetBest(List<BoundedPool> bounds, bool onlyFiniteBounds) {
+ Contract.Requires(bounds != null);
+ bounds = CombineIntegerBounds(bounds);
+ BoundedPool best = null;
+ foreach (var bound in bounds) {
+ if (!onlyFiniteBounds || bound.IsFinite) {
+ if (best == null || bound.Preference() > best.Preference()) {
+ best = bound;
+ }
+ }
+ }
+ return best;
+ }
+ static List<BoundedPool> CombineIntegerBounds(List<BoundedPool> bounds) {
+ var lowerBounds = new List<IntBoundedPool>();
+ var upperBounds = new List<IntBoundedPool>();
+ var others = new List<BoundedPool>();
+ foreach (var b in bounds) {
+ var ib = b as IntBoundedPool;
+ if (ib != null && ib.UpperBound == null) {
+ lowerBounds.Add(ib);
+ } else if (ib != null && ib.LowerBound == null) {
+ upperBounds.Add(ib);
+ } else {
+ others.Add(b);
+ }
+ }
+ // pair up the bounds
+ var n = Math.Min(lowerBounds.Count, upperBounds.Count);
+ for (var i = 0; i < n; i++) {
+ others.Add(new IntBoundedPool(lowerBounds[i].LowerBound, upperBounds[i].UpperBound));
+ }
+ for (var i = n; i < lowerBounds.Count; i++) {
+ others.Add(lowerBounds[i]);
+ }
+ for (var i = n; i < upperBounds.Count; i++) {
+ others.Add(upperBounds[i]);
+ }
+ return others;
+ }
+ }
+ public class ExactBoundedPool : BoundedPool
+ {
+ public readonly Expression E;
+ public ExactBoundedPool(Expression e) {
+ Contract.Requires(e != null);
+ E = e;
+ }
+ public override int Preference() {
+ return 20; // the best of all bounds
+ }
}
public class BoolBoundedPool : BoundedPool
{
+ public override int Preference() {
+ return 5;
+ }
+ }
+ public class CharBoundedPool : BoundedPool
+ {
+ public override int Preference() {
+ return 4;
+ }
+ }
+ public class RefBoundedPool : BoundedPool
+ {
+ public Type Type;
+ public RefBoundedPool(Type t) {
+ Type = t;
+ }
+ public override int Preference() {
+ return 2;
+ }
}
public class IntBoundedPool : BoundedPool
{
@@ -6501,36 +7150,60 @@ namespace Microsoft.Dafny {
return LowerBound != null && UpperBound != null;
}
}
+ public override int Preference() {
+ return 1;
+ }
}
public class SetBoundedPool : BoundedPool
{
public readonly Expression Set;
public SetBoundedPool(Expression set) { Set = set; }
+ public override int Preference() {
+ return 10;
+ }
}
public class SubSetBoundedPool : BoundedPool
{
public readonly Expression UpperBound;
public SubSetBoundedPool(Expression set) { UpperBound = set; }
+ public override int Preference() {
+ return 1;
+ }
}
public class SuperSetBoundedPool : BoundedPool
{
public readonly Expression LowerBound;
public SuperSetBoundedPool(Expression set) { LowerBound = set; }
+ public override int Preference() {
+ return 0;
+ }
+ public override bool IsFinite {
+ get { return false; }
+ }
}
public class MapBoundedPool : BoundedPool
{
public readonly Expression Map;
public MapBoundedPool(Expression map) { Map = map; }
+ public override int Preference() {
+ return 10;
+ }
}
public class SeqBoundedPool : BoundedPool
{
public readonly Expression Seq;
public SeqBoundedPool(Expression seq) { Seq = seq; }
+ public override int Preference() {
+ return 10;
+ }
}
public class DatatypeBoundedPool : BoundedPool
{
public readonly DatatypeDecl Decl;
public DatatypeBoundedPool(DatatypeDecl d) { Decl = d; }
+ public override int Preference() {
+ return 5;
+ }
}
public List<BoundedPool> Bounds; // initialized and filled in by resolver
@@ -6538,6 +7211,24 @@ namespace Microsoft.Dafny {
public List<BoundVar> MissingBounds; // filled in during resolution; remains "null" if bounds can be found
// invariant Bounds == null || MissingBounds == null;
+ public List<BoundVar> UncompilableBoundVars() {
+ var bvs = new List<BoundVar>();
+ if (MissingBounds != null) {
+ bvs.AddRange(MissingBounds);
+ }
+ if (Bounds != null) {
+ Contract.Assert(Bounds.Count == BoundVars.Count);
+ for (int i = 0; i < Bounds.Count; i++) {
+ var bound = Bounds[i];
+ if (bound is RefBoundedPool) {
+ // yes, this is in principle a bound, but it's not one we'd like to compile
+ bvs.Add(BoundVars[i]);
+ }
+ }
+ }
+ return bvs;
+ }
+
public ComprehensionExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)
: base(tok) {
Contract.Requires(tok != null);
@@ -6562,13 +7253,16 @@ namespace Microsoft.Dafny {
}
public abstract class QuantifierExpr : ComprehensionExpr, TypeParameter.ParentType {
+ private readonly int UniqueId;
public List<TypeParameter> TypeArgs;
private static int currentQuantId = -1;
- static int FreshQuantId()
- {
+
+ protected abstract BinaryExpr.ResolvedOpcode SplitResolvedOp { get; }
+
+ static int FreshQuantId() {
return System.Threading.Interlocked.Increment(ref currentQuantId);
}
- private readonly int UniqueId;
+
public string FullName {
get {
return "q$" + UniqueId;
@@ -6595,10 +7289,56 @@ namespace Microsoft.Dafny {
this.TypeArgs = tvars;
this.UniqueId = FreshQuantId();
}
- public abstract Expression LogicalBody();
- }
+ private Expression SplitQuantifierToExpression() {
+ Contract.Requires(SplitQuantifier != null && SplitQuantifier.Any());
+ Expression accumulator = SplitQuantifier[0];
+ for (int tid = 1; tid < SplitQuantifier.Count; tid++) {
+ accumulator = new BinaryExpr(Term.tok, SplitResolvedOp, accumulator, SplitQuantifier[tid]);
+ }
+ return accumulator;
+ }
+
+ private List<Expression> _SplitQuantifier;
+ public List<Expression> SplitQuantifier {
+ get {
+ return _SplitQuantifier;
+ }
+ set {
+ _SplitQuantifier = value;
+ SplitQuantifierExpression = SplitQuantifierToExpression();
+ }
+ }
+
+ internal Expression SplitQuantifierExpression { get; private set; }
+
+ public virtual Expression LogicalBody(bool bypassSplitQuantifier = false) {
+ // Don't call this on a quantifier with a Split clause: it's not a real quantifier. The only exception is the Compiler.
+ Contract.Requires(bypassSplitQuantifier || SplitQuantifier == null);
+ throw new cce.UnreachableException(); // This body is just here for the "Requires" clause
+ }
+
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ if (SplitQuantifier == null) {
+ foreach (var e in base.SubExpressions) {
+ yield return e;
+ }
+ } else {
+ foreach (var e in Attributes.SubExpressions(Attributes)) {
+ yield return e;
+ }
+ foreach (var e in SplitQuantifier) {
+ yield return e;
+ }
+ }
+ }
+ }
+ }
+
public class ForallExpr : QuantifierExpr {
+ protected override BinaryExpr.ResolvedOpcode SplitResolvedOp { get { return BinaryExpr.ResolvedOpcode.And; } }
+
public ForallExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)
: this(tok, new List<TypeParameter>(), bvars, range, term, attrs) {
Contract.Requires(cce.NonNullElements(bvars));
@@ -6611,7 +7351,7 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Requires(term != null);
}
- public override Expression LogicalBody() {
+ public override Expression LogicalBody(bool bypassSplitQuantifier = false) {
if (Range == null) {
return Term;
}
@@ -6623,6 +7363,8 @@ namespace Microsoft.Dafny {
}
public class ExistsExpr : QuantifierExpr {
+ protected override BinaryExpr.ResolvedOpcode SplitResolvedOp { get { return BinaryExpr.ResolvedOpcode.Or; } }
+
public ExistsExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)
: this(tok, new List<TypeParameter>(), bvars, range, term, attrs) {
Contract.Requires(cce.NonNullElements(bvars));
@@ -6635,7 +7377,7 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Requires(term != null);
}
- public override Expression LogicalBody() {
+ public override Expression LogicalBody(bool bypassSplitQuantifier = false) {
if (Range == null) {
return Term;
}
@@ -6648,9 +7390,10 @@ namespace Microsoft.Dafny {
public class SetComprehension : ComprehensionExpr
{
+ public readonly bool Finite;
public readonly bool TermIsImplicit;
- public SetComprehension(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)
+ public SetComprehension(IToken tok, bool finite, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)
: base(tok, bvars, range, term ?? new IdentifierExpr(tok, bvars[0].Name), attrs) {
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(bvars));
@@ -6658,6 +7401,7 @@ namespace Microsoft.Dafny {
Contract.Requires(range != null);
TermIsImplicit = term == null;
+ Finite = finite;
}
}
public class MapComprehension : ComprehensionExpr
@@ -6806,8 +7550,8 @@ namespace Microsoft.Dafny {
}
public class MatchExpr : Expression { // a MatchExpr is an "extended expression" and is only allowed in certain places
- public readonly Expression Source;
- public readonly List<MatchCaseExpr> Cases;
+ private Expression source;
+ private List<MatchCaseExpr> cases;
public readonly List<DatatypeCtor> MissingCases = new List<DatatypeCtor>(); // filled in during resolution
public readonly bool UsesOptionalBraces;
@@ -6823,15 +7567,32 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Requires(source != null);
Contract.Requires(cce.NonNullElements(cases));
- this.Source = source;
- this.Cases = cases;
+ this.source = source;
+ this.cases = cases;
this.UsesOptionalBraces = usesOptionalBraces;
}
+ public Expression Source {
+ get { return source; }
+ }
+
+ public List<MatchCaseExpr> Cases {
+ get { return cases; }
+ }
+
+ // should only be used in desugar in resolve to change the source and cases of the matchexpr
+ public void UpdateSource(Expression source) {
+ this.source = source;
+ }
+
+ public void UpdateCases(List<MatchCaseExpr> cases) {
+ this.cases = cases;
+ }
+
public override IEnumerable<Expression> SubExpressions {
get {
yield return Source;
- foreach (var mc in Cases) {
+ foreach (var mc in cases) {
yield return mc.Body;
}
}
@@ -6913,12 +7674,13 @@ namespace Microsoft.Dafny {
public readonly IToken tok;
public readonly string Id;
public DatatypeCtor Ctor; // filled in by resolution
- public readonly List<BoundVar> Arguments;
+ public List<BoundVar> Arguments; // created by the resolver.
+ public List<CasePattern> CasePatterns; // generated from parsers. It should be converted to List<BoundVar> during resolver. Invariant: CasePatterns != null ==> Arguments == null
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(tok != null);
Contract.Invariant(Id != null);
- Contract.Invariant(cce.NonNullElements(Arguments));
+ Contract.Invariant(cce.NonNullElements(Arguments) || cce.NonNullElements(CasePatterns));
}
public MatchCase(IToken tok, string id, [Captured] List<BoundVar> arguments) {
@@ -6929,24 +7691,51 @@ namespace Microsoft.Dafny {
this.Id = id;
this.Arguments = arguments;
}
+
+ public MatchCase(IToken tok, string id, [Captured] List<CasePattern> cps) {
+ Contract.Requires(tok != null);
+ Contract.Requires(id != null);
+ Contract.Requires(cce.NonNullElements(cps));
+ this.tok = tok;
+ this.Id = id;
+ this.CasePatterns = cps;
+ }
}
public class MatchCaseExpr : MatchCase
{
- public readonly Expression Body;
+ private Expression body;
[ContractInvariantMethod]
void ObjectInvariant() {
- Contract.Invariant(Body != null);
+ Contract.Invariant(body != null);
}
public MatchCaseExpr(IToken tok, string id, [Captured] List<BoundVar> arguments, Expression body)
- : base(tok, id, arguments)
- {
+ : base(tok, id, arguments) {
Contract.Requires(tok != null);
Contract.Requires(id != null);
Contract.Requires(cce.NonNullElements(arguments));
Contract.Requires(body != null);
- this.Body = body;
+ this.body = body;
+ }
+
+ public MatchCaseExpr(IToken tok, string id, [Captured] List<CasePattern> cps, Expression body)
+ : base(tok, id, cps)
+ {
+ Contract.Requires(tok != null);
+ Contract.Requires(id != null);
+ Contract.Requires(cce.NonNullElements(cps));
+ Contract.Requires(body != null);
+ this.body = body;
+ }
+
+ public Expression Body {
+ get { return body; }
+ }
+
+ // should only be called by resolve to reset the body of the MatchCaseExpr
+ public void UpdateBody(Expression body) {
+ this.body = body;
}
}
@@ -7122,6 +7911,36 @@ namespace Microsoft.Dafny {
}
}
+ public class DatatypeUpdateExpr : ConcreteSyntaxExpression
+ {
+ public readonly Expression Root;
+ public readonly List<Tuple<IToken, string, Expression>> Updates;
+ public DatatypeUpdateExpr(IToken tok, Expression root, List<Tuple<IToken, string, Expression>> updates)
+ : base(tok) {
+ Contract.Requires(tok != null);
+ Contract.Requires(root != null);
+ Contract.Requires(updates != null);
+ Contract.Requires(updates.Count != 0);
+ Root = root;
+ Updates = updates;
+ }
+
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ if (ResolvedExpression == null) {
+ yield return Root;
+ foreach (var update in Updates) {
+ yield return update.Item3;
+ }
+ } else {
+ foreach (var e in ResolvedExpression.SubExpressions) {
+ yield return e;
+ }
+ }
+ }
+ }
+ }
+
/// <summary>
/// An AutoGeneratedExpression is simply a wrapper around an expression. This expression tells the generation of hover text (in the Dafny IDE)
@@ -7348,6 +8167,48 @@ namespace Microsoft.Dafny {
public class BottomUpVisitor
{
+ public void Visit(IEnumerable<Expression> exprs) {
+ exprs.Iter(Visit);
+ }
+ public void Visit(IEnumerable<Statement> stmts) {
+ stmts.Iter(Visit);
+ }
+ public void Visit(MaybeFreeExpression expr) {
+ Visit(expr.E);
+ }
+ public void Visit(FrameExpression expr) {
+ Visit(expr.E);
+ }
+ public void Visit(IEnumerable<MaybeFreeExpression> exprs) {
+ exprs.Iter(Visit);
+ }
+ public void Visit(IEnumerable<FrameExpression> exprs) {
+ exprs.Iter(Visit);
+ }
+ public void Visit(ICallable decl) {
+ if (decl is Function) {
+ Visit((Function)decl);
+ } else if (decl is Method) {
+ Visit((Method)decl);
+ }
+ //TODO More?
+ }
+ public void Visit(Method method) {
+ Visit(method.Ens);
+ Visit(method.Req);
+ Visit(method.Mod.Expressions);
+ Visit(method.Decreases.Expressions);
+ if (method.Body != null) { Visit(method.Body); }
+ //TODO More?
+ }
+ public void Visit(Function function) {
+ Visit(function.Ens);
+ Visit(function.Req);
+ Visit(function.Reads);
+ Visit(function.Decreases.Expressions);
+ if (function.Body != null) { Visit(function.Body); }
+ //TODO More?
+ }
public void Visit(Expression expr) {
Contract.Requires(expr != null);
// recursively visit all subexpressions and all substatements
@@ -7397,6 +8258,48 @@ namespace Microsoft.Dafny {
stmt.SubStatements.Iter(s => Visit(s, st));
}
}
+ public void Visit(IEnumerable<Expression> exprs, State st) {
+ exprs.Iter(e => Visit(e, st));
+ }
+ public void Visit(IEnumerable<Statement> stmts, State st) {
+ stmts.Iter(e => Visit(e, st));
+ }
+ public void Visit(MaybeFreeExpression expr, State st) {
+ Visit(expr.E, st);
+ }
+ public void Visit(FrameExpression expr, State st) {
+ Visit(expr.E, st);
+ }
+ public void Visit(IEnumerable<MaybeFreeExpression> exprs, State st) {
+ exprs.Iter(e => Visit(e, st));
+ }
+ public void Visit(IEnumerable<FrameExpression> exprs, State st) {
+ exprs.Iter(e => Visit(e, st));
+ }
+ public void Visit(ICallable decl, State st) {
+ if (decl is Function) {
+ Visit((Function)decl, st);
+ } else if (decl is Method) {
+ Visit((Method)decl, st);
+ }
+ //TODO More?
+ }
+ public void Visit(Method method, State st) {
+ Visit(method.Ens, st);
+ Visit(method.Req, st);
+ Visit(method.Mod.Expressions, st);
+ Visit(method.Decreases.Expressions, st);
+ if (method.Body != null) { Visit(method.Body, st); }
+ //TODO More?
+ }
+ public void Visit(Function function, State st) {
+ Visit(function.Ens, st);
+ Visit(function.Req, st);
+ Visit(function.Reads, st);
+ Visit(function.Decreases.Expressions, st);
+ if (function.Body != null) { Visit(function.Body, st); }
+ //TODO More?
+ }
/// <summary>
/// Visit one expression proper. This method is invoked before it is invoked on the
/// sub-parts (sub-expressions and sub-statements). A return value of "true" says to
diff --git a/Source/Dafny/DafnyMain.cs b/Source/Dafny/DafnyMain.cs
index 012ca4df..fd2e00fb 100644
--- a/Source/Dafny/DafnyMain.cs
+++ b/Source/Dafny/DafnyMain.cs
@@ -12,7 +12,7 @@ using Bpl = Microsoft.Boogie;
namespace Microsoft.Dafny {
public class Main {
- private static void MaybePrintProgram(Program program, string filename)
+ private static void MaybePrintProgram(Program program, string filename, bool afterResolver)
{
if (filename != null) {
TextWriter tw;
@@ -22,14 +22,14 @@ namespace Microsoft.Dafny {
tw = new System.IO.StreamWriter(filename);
}
Printer pr = new Printer(tw, DafnyOptions.O.PrintMode);
- pr.PrintProgram(program);
+ pr.PrintProgram(program, afterResolver);
}
}
/// <summary>
/// Returns null on success, or an error string otherwise.
/// </summary>
- public static string ParseCheck(IList<string/*!*/>/*!*/ fileNames, string/*!*/ programName, out Program program)
+ public static string ParseCheck(IList<string/*!*/>/*!*/ fileNames, string/*!*/ programName, ErrorReporter reporter, out Program program)
//modifies Bpl.CommandLineOptions.Clo.XmlSink.*;
{
Contract.Requires(programName != null);
@@ -47,31 +47,31 @@ namespace Microsoft.Dafny {
Console.WriteLine("Parsing " + dafnyFileName);
}
- string err = ParseFile(dafnyFileName, Bpl.Token.NoToken, module, builtIns, new Errors());
+ string err = ParseFile(dafnyFileName, Bpl.Token.NoToken, module, builtIns, new Errors(reporter));
if (err != null) {
return err;
}
}
if (!DafnyOptions.O.DisallowIncludes) {
- string errString = ParseIncludes(module, builtIns, fileNames, new Errors());
+ string errString = ParseIncludes(module, builtIns, fileNames, new Errors(reporter));
if (errString != null) {
return errString;
}
}
- program = new Program(programName, module, builtIns);
+ program = new Program(programName, module, builtIns, reporter);
- MaybePrintProgram(program, DafnyOptions.O.DafnyPrintFile);
+ MaybePrintProgram(program, DafnyOptions.O.DafnyPrintFile, false);
if (Bpl.CommandLineOptions.Clo.NoResolve || Bpl.CommandLineOptions.Clo.NoTypecheck) { return null; }
Dafny.Resolver r = new Dafny.Resolver(program);
r.ResolveProgram(program);
- MaybePrintProgram(program, DafnyOptions.O.DafnyPrintResolvedFile);
+ MaybePrintProgram(program, DafnyOptions.O.DafnyPrintResolvedFile, true);
- if (r.ErrorCount != 0) {
- return string.Format("{0} resolution/type errors detected in {1}", r.ErrorCount, program.Name);
+ if (reporter.Count(ErrorLevel.Error) != 0) {
+ return string.Format("{0} resolution/type errors detected in {1}", reporter.Count(ErrorLevel.Error), program.Name);
}
return null; // success
diff --git a/Source/Dafny/DafnyOptions.cs b/Source/Dafny/DafnyOptions.cs
index 4fc2de96..9258503b 100644
--- a/Source/Dafny/DafnyOptions.cs
+++ b/Source/Dafny/DafnyOptions.cs
@@ -9,18 +9,26 @@ namespace Microsoft.Dafny
{
public class DafnyOptions : Bpl.CommandLineOptions
{
- public DafnyOptions()
+ private ErrorReporter errorReporter;
+
+ public DafnyOptions(ErrorReporter errorReporter = null)
: base("Dafny", "Dafny program verifier") {
+ this.errorReporter = errorReporter;
+ SetZ3ExecutableName();
}
public override string VersionNumber {
get {
- return System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion;
+ return System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion
+#if ENABLE_IRONDAFNY
+ + "[IronDafny]"
+#endif
+ ;
}
}
public override string VersionSuffix {
get {
- return " version " + VersionNumber + ", Copyright (c) 2003-2015, Microsoft.";
+ return " version " + VersionNumber + ", Copyright (c) 2003-2016, Microsoft.";
}
}
@@ -35,6 +43,7 @@ namespace Microsoft.Dafny
Bpl.CommandLineOptions.Install(options);
}
+ public bool UnicodeOutput = false;
public bool DisallowSoundnessCheating = false;
public bool Dafnycc = false;
public int Induction = 3;
@@ -42,9 +51,10 @@ namespace Microsoft.Dafny
public string DafnyPrelude = null;
public string DafnyPrintFile = null;
public enum PrintModes { Everything, NoIncludes, NoGhost };
- public PrintModes PrintMode;
+ public PrintModes PrintMode = PrintModes.Everything; // Default to printing everything
public bool DafnyVerify = true;
public string DafnyPrintResolvedFile = null;
+ public List<string> DafnyPrintExportedViews = new List<string>();
public bool Compile = true;
public bool ForceCompile = false;
public bool RunAfterCompile = false;
@@ -54,6 +64,21 @@ namespace Microsoft.Dafny
public string AutoReqPrintFile = null;
public bool ignoreAutoReq = false;
public bool AllowGlobals = false;
+ public bool CountVerificationErrors = true;
+ public bool Optimize = false;
+ public bool AutoTriggers = true;
+ public bool RewriteFocalPredicates = true;
+ public bool PrintTooltips = false;
+ public bool PrintStats = false;
+ public bool PrintFunctionCallGraph = false;
+ public bool WarnShadowing = false;
+ public bool IronDafny =
+#if ENABLE_IRONDAFNY
+ true
+#else
+ false
+#endif
+ ;
protected override bool ParseOption(string name, Bpl.CommandLineOptionEngine.CommandLineParseState ps) {
var args = ps.args; // convenient synonym
@@ -96,6 +121,11 @@ namespace Microsoft.Dafny
DafnyPrintResolvedFile = args[ps.i];
}
return true;
+ case "view":
+ if (ps.ConfirmArgumentCount(1)) {
+ DafnyPrintExportedViews = args[ps.i].Split(',').ToList();
+ }
+ return true;
case "compile": {
int compile = 0;
@@ -154,7 +184,7 @@ namespace Microsoft.Dafny
case "noNLarith":
DisableNLarith = true;
- this.AddZ3Option("NL_ARITH=false");
+ this.AddZ3Option("smt.arith.nl=false");
return true;
case "autoReqPrint":
@@ -170,6 +200,61 @@ namespace Microsoft.Dafny
case "allowGlobals":
AllowGlobals = true;
return true;
+
+ case "stats":
+ PrintStats = true;
+ return true;
+
+ case "funcCallGraph":
+ PrintFunctionCallGraph = true;
+ return true;
+
+ case "warnShadowing":
+ WarnShadowing = true;
+ return true;
+
+ case "countVerificationErrors": {
+ int countErrors = 1; // defaults to reporting verification errors
+ if (ps.GetNumericArgument(ref countErrors, 2)) {
+ CountVerificationErrors = countErrors == 1;
+ }
+ return true;
+ }
+
+ case "printTooltips":
+ PrintTooltips = true;
+ return true;
+
+ case "autoTriggers": {
+ int autoTriggers = 0;
+ if (ps.GetNumericArgument(ref autoTriggers, 2)) {
+ AutoTriggers = autoTriggers == 1;
+ }
+ return true;
+ }
+
+ case "rewriteFocalPredicates": {
+ int rewriteFocalPredicates = 0;
+ if (ps.GetNumericArgument(ref rewriteFocalPredicates, 2)) {
+ RewriteFocalPredicates = rewriteFocalPredicates == 1;
+ }
+ return true;
+ }
+
+ case "optimize": {
+ Optimize = true;
+ return true;
+ }
+
+ case "noIronDafny": {
+ IronDafny = false;
+ return true;
+ }
+
+ case "ironDafny": {
+ IronDafny = true;
+ return true;
+ }
default:
break;
@@ -190,6 +275,39 @@ namespace Microsoft.Dafny
// TODO: provide attribute help here
}
+
+ /// <summary>
+ /// Dafny comes with it's own copy of z3, to save new users the trouble of having to install extra dependency.
+ /// For this to work, Dafny makes the Z3ExecutablePath point to the path were Z3 is put by our release script.
+ /// For developers though (and people getting this from source), it's convenient to be able to run right away,
+ /// so we vendor a Windows version.
+ /// </summary>
+ private void SetZ3ExecutableName() {
+ var platform = (int)System.Environment.OSVersion.Platform;
+
+ // http://www.mono-project.com/docs/faq/technical/
+ var isUnix = platform == 4 || platform == 128;
+
+ var z3binName = isUnix ? "z3" : "z3.exe";
+ var dafnyBinDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
+ var z3BinDir = System.IO.Path.Combine(dafnyBinDir, "z3", "bin");
+ var z3BinPath = System.IO.Path.Combine(z3BinDir, z3binName);
+
+ if (!System.IO.File.Exists(z3BinPath) && !isUnix) {
+ // This is most likely a Windows user running from source without downloading z3
+ // separately; this is ok, since we vendor z3.exe.
+ z3BinPath = System.IO.Path.Combine(dafnyBinDir, z3binName);
+ }
+
+ if (!System.IO.File.Exists(z3BinPath) && errorReporter != null) {
+ var tok = new Bpl.Token(1, 1) { filename = "*** " };
+ errorReporter.Warning(MessageSource.Other, tok, "Could not find '{0}' in '{1}'.{2}Downloading and extracting a Z3 distribution to Dafny's 'Binaries' folder would solve this issue; for now, we'll rely on Boogie to find Z3.",
+ z3binName, z3BinDir, System.Environment.NewLine);
+ } else {
+ Z3ExecutablePath = z3BinPath;
+ }
+ }
+
public override void Usage() {
Console.WriteLine(@" ---- Dafny options ---------------------------------------------------------
@@ -202,6 +320,7 @@ namespace Microsoft.Dafny
print Dafny program after parsing it
(use - as <file> to print to console)
/printMode:<Everything|NoIncludes|NoGhost>
+ Everything is the default.
NoIncludes disables printing of {:verify false} methods incorporated via the
include mechanism, as well as datatypes and fields included from other files.
NoGhost disables printing of functions, ghost methods, and proof statements in
@@ -209,6 +328,11 @@ namespace Microsoft.Dafny
/rprint:<file>
print Dafny program after resolving it
(use - as <file> to print to console)
+ /view:<view1, view2>
+ print the filtered views of a module after it is resolved (/rprint).
+ if print before the module is resolved (/dprint), then everthing in the module is printed
+ if no view is specified, then everything in the module is printed.
+
/dafnyVerify:<n>
0 - stop after typechecking
1 - continue on to translation, verification, and compilation
@@ -237,7 +361,7 @@ namespace Microsoft.Dafny
2 - apply induction as requested (by attributes) and also
for heuristically chosen quantifiers
3 (default) - apply induction as requested, and for
- heuristically chosen quantifiers and ghost methods
+ heuristically chosen quantifiers and lemmas
/inductionHeuristic:<n>
0 - least discriminating induction heuristic (that is, lean
toward applying induction more often)
@@ -245,17 +369,47 @@ namespace Microsoft.Dafny
how discriminating they are: 0 < 1 < 2 < (3,4) < 5 < 6
6 (default) - most discriminating
/noIncludes Ignore include directives
- /noNLarith Reduce Z3's knowledge of non-linear arithmetic (*,/,%).
+ /noNLarith Reduce Z3's knowledge of non-linear arithmetic (*,/,%).
Results in more manual work, but also produces more predictable behavior.
/autoReqPrint:<file>
Print out requirements that were automatically generated by autoReq.
/noAutoReq Ignore autoReq attributes
/allowGlobals Allow the implicit class '_default' to contain fields, instance functions,
and instance methods. These class members are declared at the module scope,
- outside of explicit classes. This command-line option is provided to simply
+ outside of explicit classes. This command-line option is provided to simplify
a transition from the behavior in the language prior to version 1.9.3, from
which point onward all functions and methods declared at the module scope are
implicitly static and fields declarations are not allowed at the module scope.
+ /countVerificationErrors:<n>
+ 0 - If preprocessing succeeds, set exit code to 0 regardless of the number
+ of verification errors.
+ 1 (default) - If preprocessing succeeds, set exit code to the number of
+ verification errors.
+ /autoTriggers:<n>
+ 0 - Do not generate {:trigger} annotations for user-level quantifiers.
+ 1 (default) - Add a {:trigger} to each user-level quantifier. Existing
+ annotations are preserved.
+ /rewriteFocalPredicates:<n>
+ 0 - Don't rewrite predicates in the body of prefix lemmas.
+ 1 (default) - In the body of prefix lemmas, rewrite any use of a focal predicate
+ P to P#[_k-1].
+ /optimize Produce optimized C# code, meaning:
+ - selects optimized C# prelude by passing
+ /define:DAFNY_USE_SYSTEM_COLLECTIONS_IMMUTABLE to csc.exe (requires
+ System.Collections.Immutable.dll in the source directory to successfully
+ compile).
+ - passes /optimize flag to csc.exe.
+ /stats Print interesting statistics about the Dafny files supplied.
+ /funcCallGraph Print out the function call graph. Format is: func,mod=callee*
+ /warnShadowing Emits a warning if the name of a declared variable caused another variable
+ to be shadowed
+ /ironDafny Enable experimental features needed to support Ironclad/Ironfleet. Use of
+ these features may cause your code to become incompatible with future
+ releases of Dafny.
+ /noIronDafny Disable Ironclad/Ironfleet features, if enabled by default.
+ /printTooltips
+ Dump additional positional information (displayed as mouse-over tooltips by
+ the VS plugin) to stdout as 'Info' messages.
");
base.Usage(); // also print the Boogie options
}
diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj
index 74f7dae6..501a624c 100644
--- a/Source/Dafny/DafnyPipeline.csproj
+++ b/Source/Dafny/DafnyPipeline.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -8,7 +8,7 @@
<ProjectGuid>{FE44674A-1633-4917-99F4-57635E6FA740}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>DafnyPipeline</RootNamespace>
+ <RootNamespace>Microsoft.Dafny</RootNamespace>
<AssemblyName>DafnyPipeline</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
@@ -41,7 +41,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DefineConstants>TRACE;DEBUG;NO_ENABLE_IRONDAFNY</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
@@ -83,7 +83,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
+ <DefineConstants>TRACE;NO_ENABLE_IRONDAFNY</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
@@ -91,7 +91,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Checked\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DefineConstants>TRACE;DEBUG;NO_ENABLE_IRONDAFNY</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
@@ -143,8 +143,16 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Cloner.cs" />
+ <Compile Include="Reporting.cs" />
+ <Compile Include="Triggers\QuantifiersCollection.cs" />
+ <Compile Include="Triggers\QuantifierSplitter.cs" />
+ <Compile Include="Triggers\TriggerExtensions.cs" />
+ <Compile Include="Triggers\QuantifiersCollector.cs" />
+ <Compile Include="Triggers\TriggersCollector.cs" />
+ <Compile Include="Triggers\TriggerUtils.cs" />
<Compile Include="Util.cs" />
<Compile Include="Compiler.cs" />
+ <Compile Include="BigIntegerParser.cs" />
<Compile Include="DafnyAst.cs" />
<Compile Include="DafnyMain.cs" />
<Compile Include="DafnyOptions.cs" />
@@ -191,4 +199,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project> \ No newline at end of file
diff --git a/Source/Dafny/Makefile b/Source/Dafny/Makefile
index 4c01c780..68ab7a2d 100644
--- a/Source/Dafny/Makefile
+++ b/Source/Dafny/Makefile
@@ -4,8 +4,8 @@
# from http://boogiepartners.codeplex.com/. Update the FRAME_DIR variable to
# point to whatever directory you install that into.
# ###############################################################################
-COCO_EXE_DIR = ..\..\..\boogiepartners\CocoRdownload
-FRAME_DIR = ..\..\..\boogiepartners\CocoR\Modified
+COCO_EXE_DIR = ..\..\..\boogie-partners\CocoR\bin
+FRAME_DIR = ..\..\..\boogie-partners\CocoR\Modified
COCO = $(COCO_EXE_DIR)\Coco.exe
# "all" depends on 2 files, really (Parser.cs and Scanner.cs), but they
diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs
index 9e283ef5..f64ba7fa 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -27,76 +27,181 @@ public class Parser {
public const int _object = 11;
public const int _string = 12;
public const int _set = 13;
- public const int _multiset = 14;
- public const int _seq = 15;
- public const int _map = 16;
- public const int _imap = 17;
- public const int _charToken = 18;
- public const int _stringToken = 19;
- public const int _colon = 20;
- public const int _comma = 21;
- public const int _verticalbar = 22;
- public const int _doublecolon = 23;
- public const int _bullet = 24;
- public const int _dot = 25;
- public const int _semi = 26;
- public const int _darrow = 27;
- public const int _arrow = 28;
- public const int _assume = 29;
- public const int _calc = 30;
- public const int _case = 31;
- public const int _then = 32;
- public const int _else = 33;
- public const int _decreases = 34;
- public const int _invariant = 35;
- public const int _function = 36;
- public const int _predicate = 37;
- public const int _inductive = 38;
- public const int _lemma = 39;
- public const int _copredicate = 40;
- public const int _modifies = 41;
- public const int _reads = 42;
- public const int _requires = 43;
- public const int _lbrace = 44;
- public const int _rbrace = 45;
- public const int _lbracket = 46;
- public const int _rbracket = 47;
- public const int _openparen = 48;
- public const int _closeparen = 49;
- public const int _openAngleBracket = 50;
- public const int _closeAngleBracket = 51;
- public const int _eq = 52;
- public const int _neq = 53;
- public const int _neqAlt = 54;
- public const int _star = 55;
- public const int _notIn = 56;
- public const int _ellipsis = 57;
- public const int maxT = 136;
+ public const int _iset = 14;
+ public const int _multiset = 15;
+ public const int _seq = 16;
+ public const int _map = 17;
+ public const int _imap = 18;
+ public const int _charToken = 19;
+ public const int _stringToken = 20;
+ public const int _colon = 21;
+ public const int _comma = 22;
+ public const int _verticalbar = 23;
+ public const int _doublecolon = 24;
+ public const int _boredSmiley = 25;
+ public const int _bullet = 26;
+ public const int _dot = 27;
+ public const int _semi = 28;
+ public const int _darrow = 29;
+ public const int _arrow = 30;
+ public const int _assume = 31;
+ public const int _calc = 32;
+ public const int _case = 33;
+ public const int _then = 34;
+ public const int _else = 35;
+ public const int _decreases = 36;
+ public const int _invariant = 37;
+ public const int _function = 38;
+ public const int _predicate = 39;
+ public const int _inductive = 40;
+ public const int _lemma = 41;
+ public const int _copredicate = 42;
+ public const int _modifies = 43;
+ public const int _reads = 44;
+ public const int _requires = 45;
+ public const int _lbrace = 46;
+ public const int _rbrace = 47;
+ public const int _lbracket = 48;
+ public const int _rbracket = 49;
+ public const int _openparen = 50;
+ public const int _closeparen = 51;
+ public const int _openAngleBracket = 52;
+ public const int _closeAngleBracket = 53;
+ public const int _eq = 54;
+ public const int _neq = 55;
+ public const int _neqAlt = 56;
+ public const int _star = 57;
+ public const int _notIn = 58;
+ public const int _ellipsis = 59;
+ public const int maxT = 140;
const bool _T = true;
const bool _x = false;
const int minErrDist = 2;
- public Scanner/*!*/ scanner;
- public Errors/*!*/ errors;
+ public Scanner scanner;
+ public Errors errors;
- public Token/*!*/ t; // last recognized token
- public Token/*!*/ la; // lookahead token
+ public Token t; // last recognized token
+ public Token la; // lookahead token
int errDist = minErrDist;
readonly Expression/*!*/ dummyExpr;
readonly AssignmentRhs/*!*/ dummyRhs;
-readonly FrameExpression/*!*/ dummyFrameExpr;
+readonly FrameExpression/*!*/ dummyFrameExpr;
readonly Statement/*!*/ dummyStmt;
readonly ModuleDecl theModule;
readonly BuiltIns theBuiltIns;
readonly bool theVerifyThisFile;
int anonymousIds = 0;
-struct MemberModifiers {
+/// <summary>
+/// Holds the modifiers given for a declaration
+///
+/// Not all modifiers are applicable to all kinds of declarations.
+/// Errors are given when a modify does not apply.
+/// We also record the tokens for the specified modifiers so that
+/// they can be used in error messages.
+/// </summary>
+struct DeclModifierData {
+ public bool IsAbstract;
+ public IToken AbstractToken;
public bool IsGhost;
+ public IToken GhostToken;
public bool IsStatic;
+ public IToken StaticToken;
public bool IsProtected;
+ public IToken ProtectedToken;
+ public bool IsExtern;
+ public IToken ExternToken;
+ public StringLiteralExpr ExternName;
+
+}
+
+// Check that token has not been set, then set it.
+public void CheckAndSetToken(ref IToken token)
+{
+ if (token != null) {
+ SemErr(t, "Duplicate declaration modifier: " + t.val);
+ }
+ token = t;
+}
+
+/// <summary>
+// A flags type used to tell what declaration modifiers are allowed for a declaration.
+/// </summary>
+[Flags]
+enum AllowedDeclModifiers {
+ None = 0,
+ Abstract = 1,
+ Ghost = 2,
+
+ // Means ghost not allowed because already implicitly ghost.
+ AlreadyGhost = 4,
+ Static = 8,
+ Protected = 16,
+ Extern = 32
+};
+
+/// <summary>
+/// Check the declaration modifiers against those that are allowed.
+///
+/// The 'allowed' parameter specifies which declaratio modifiers are allowed.
+/// The 'declCaption' parameter should be a string describing the kind of declaration.
+/// It is used in error messages.
+/// Any declaration modifiers that are present but not allowed are cleared.
+///</summary>
+void CheckDeclModifiers(DeclModifierData dmod, string declCaption, AllowedDeclModifiers allowed)
+{
+ if (dmod.IsAbstract && ((allowed & AllowedDeclModifiers.Abstract) == 0)) {
+ SemErr(dmod.AbstractToken, declCaption + " cannot be declared 'abstract'.");
+ dmod.IsAbstract = false;
+ }
+ if (dmod.IsGhost) {
+ if ((allowed & AllowedDeclModifiers.AlreadyGhost) != 0) {
+ SemErr(dmod.GhostToken, declCaption + " cannot be declared ghost (they are 'ghost' by default).");
+ dmod.IsGhost = false;
+ } else if ((allowed & AllowedDeclModifiers.Ghost) == 0) {
+ SemErr(dmod.GhostToken, declCaption + " cannot be declared 'ghost'.");
+ dmod.IsGhost = false;
+ }
+ }
+ if (dmod.IsStatic && ((allowed & AllowedDeclModifiers.Static) == 0)) {
+ SemErr(dmod.StaticToken, declCaption + " cannot be declared 'static'.");
+ dmod.IsStatic = false;
+ }
+ if (dmod.IsProtected && ((allowed & AllowedDeclModifiers.Protected) == 0)) {
+ SemErr(dmod.ProtectedToken, declCaption + " cannot be declared 'protected'.");
+ dmod.IsProtected = false;
+ }
+ if (dmod.IsExtern && ((allowed & AllowedDeclModifiers.Extern) == 0)) {
+ SemErr(dmod.ExternToken, declCaption + " cannot be declared 'extern'.");
+ dmod.IsExtern = false;
+ }
+}
+
+/// <summary>
+/// Encode an 'extern' declaration modifier as an {:extern name} attribute.
+///
+/// We also include an {:axiom} attribute since the specification of an
+/// external entity is assumed to hold, but only for methods or functions.
+///</summary>
+static void EncodeExternAsAttribute(DeclModifierData dmod, ref Attributes attrs, IToken/*!*/ id, bool needAxiom) {
+ if (dmod.IsExtern) {
+ StringLiteralExpr name = dmod.ExternName;
+ if (name == null) {
+ bool isVerbatimString = false;
+ name = new StringLiteralExpr(id, id.val, isVerbatimString);
+ }
+ var args = new List<Expression>();
+ args.Add(name);
+ attrs = new Attributes("extern", args, attrs);
+
+ // Also 'extern' implies 'axiom' for methods or functions.
+ if (needAxiom) {
+ attrs = new Attributes("axiom", new List<Expression>(), attrs);
+ }
+ }
}
///<summary>
@@ -111,11 +216,11 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built
string s;
if (filename == "stdin.dfy") {
s = Microsoft.Boogie.ParserHelper.Fill(System.Console.In, new List<string>());
- return Parse(s, filename, module, builtIns, errors, verifyThisFile);
+ return Parse(s, filename, filename, module, builtIns, errors, verifyThisFile);
} else {
using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) {
s = Microsoft.Boogie.ParserHelper.Fill(reader, new List<string>());
- return Parse(s, DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, module, builtIns, errors, verifyThisFile);
+ return Parse(s, filename, DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, module, builtIns, errors, verifyThisFile);
}
}
}
@@ -125,12 +230,12 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built
/// Returns the number of parsing errors encountered.
/// Note: first initialize the Scanner.
///</summary>
-public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) {
+public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) {
Contract.Requires(s != null);
Contract.Requires(filename != null);
Contract.Requires(module != null);
- Errors errors = new Errors();
- return Parse(s, filename, module, builtIns, errors, verifyThisFile);
+ Errors errors = new Errors(reporter);
+ return Parse(s, fullFilename, filename, module, builtIns, errors, verifyThisFile);
}
///<summary>
/// Parses top-level things (modules, classes, datatypes, class members)
@@ -138,18 +243,18 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module,
/// Returns the number of parsing errors encountered.
/// Note: first initialize the Scanner with the given Errors sink.
///</summary>
-public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns,
- Errors/*!*/ errors, bool verifyThisFile=true) {
+public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module,
+ BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {
Contract.Requires(s != null);
Contract.Requires(filename != null);
Contract.Requires(module != null);
Contract.Requires(errors != null);
byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
- Scanner scanner = new Scanner(ms, errors, filename);
+ Scanner scanner = new Scanner(ms, errors, fullFilename, filename);
Parser parser = new Parser(scanner, errors, module, builtIns, verifyThisFile);
parser.Parse();
- return parser.errors.count;
+ return parser.errors.ErrorCount;
}
public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true)
: this(scanner, errors) // the real work
@@ -174,6 +279,25 @@ bool IsAlternative() {
return la.kind == _lbrace && x.kind == _case;
}
+// an existential guard starts with an identifier and is then followed by
+// * a colon (if the first identifier is given an explicit type),
+// * a comma (if there's a list a bound variables and the first one is not given an explicit type),
+// * a start-attribute (if there's one bound variable and it is not given an explicit type and there are attributes), or
+// * a bored smiley (if there's one bound variable and it is not given an explicit type).
+bool IsExistentialGuard() {
+ scanner.ResetPeek();
+ if (la.kind == _ident) {
+ Token x = scanner.Peek();
+ if (x.kind == _colon || x.kind == _comma || x.kind == _boredSmiley) {
+ return true;
+ } else if (x.kind == _lbrace) {
+ x = scanner.Peek();
+ return x.kind == _colon;
+ }
+ }
+ return false;
+}
+
bool IsLoopSpec() {
return la.kind == _invariant | la.kind == _decreases | la.kind == _modifies;
}
@@ -245,6 +369,9 @@ bool IsMapDisplay() {
bool IsIMapDisplay() {
return la.kind == _imap && scanner.Peek().kind == _lbracket;
}
+bool IsISetDisplay() {
+ return la.kind == _iset && scanner.Peek().kind == _lbrace;
+}
bool IsSuffix() {
return la.kind == _dot || la.kind == _lbracket || la.kind == _openparen;
@@ -366,6 +493,9 @@ bool IsGenericInstantiation() {
return false;
}
}
+/* Returns true if the next thing is of the form:
+ * "<" Type { "," Type } ">"
+ */
bool IsTypeList(ref IToken pt) {
if (pt.kind != _openAngleBracket) {
return false;
@@ -373,6 +503,10 @@ bool IsTypeList(ref IToken pt) {
pt = scanner.Peek();
return IsTypeSequence(ref pt, _closeAngleBracket);
}
+/* Returns true if the next thing is of the form:
+ * Type { "," Type }
+ * followed by an endBracketKind.
+ */
bool IsTypeSequence(ref IToken pt, int endBracketKind) {
while (true) {
if (!IsType(ref pt)) {
@@ -404,12 +538,13 @@ bool IsType(ref IToken pt) {
return true;
case _arrayToken:
case _set:
+ case _iset:
case _multiset:
case _seq:
case _map:
case _imap:
pt = scanner.Peek();
- return IsTypeList(ref pt);
+ return pt.kind != _openAngleBracket || IsTypeList(ref pt);
case _ident:
while (true) {
// invariant: next token is an ident
@@ -428,19 +563,31 @@ bool IsType(ref IToken pt) {
}
case _openparen:
pt = scanner.Peek();
+ if (pt.kind == _closeparen) {
+ // end of type list
+ pt = scanner.Peek();
+ return true;
+ }
return IsTypeSequence(ref pt, _closeparen);
default:
return false;
}
}
+
+bool IsDefaultImport() {
+ scanner.ResetPeek();
+ Token x = scanner.Peek(); // lookahead token again
+ return la.val == "default" && x.val != "export";
+}
+
/*--------------------------------------------------------------------------*/
- public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors) {
+ public Parser(Scanner scanner, Errors errors) {
this.scanner = scanner;
this.errors = errors;
- Token/*!*/ tok = new Token();
+ Token tok = new Token();
tok.val = "";
this.la = tok;
this.t = new Token(); // just to satisfy its non-null constraint
@@ -451,13 +598,13 @@ bool IsType(ref IToken pt) {
errDist = 0;
}
- public void SemErr (string/*!*/ msg) {
+ public void SemErr (string msg) {
Contract.Requires(msg != null);
if (errDist >= minErrDist) errors.SemErr(t, msg);
errDist = 0;
}
- public void SemErr(IToken/*!*/ tok, string/*!*/ msg) {
+ public void SemErr(IToken tok, string msg) {
Contract.Requires(tok != null);
Contract.Requires(msg != null);
errors.SemErr(tok, msg);
@@ -506,20 +653,17 @@ bool IsType(ref IToken pt) {
void Dafny() {
- ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;
List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();
- ModuleDecl submodule;
// to support multiple files, create a default module only if theModule is null
DefaultModuleDecl defaultModule = (DefaultModuleDecl)((LiteralModuleDecl)theModule).ModuleDef;
// theModule should be a DefaultModuleDecl (actually, the singular DefaultModuleDecl)
- TraitDecl/*!*/ trait;
Contract.Assert(defaultModule != null);
- while (la.kind == 58) {
+ while (la.kind == 60) {
Get();
- Expect(19);
+ Expect(20);
{
- string parsedFile = t.filename;
+ string parsedFile = scanner.FullFilename;
bool isVerbatimString;
string includedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);
includedFile = Util.RemoveEscaping(includedFile, isVerbatimString);
@@ -534,47 +678,7 @@ bool IsType(ref IToken pt) {
}
while (StartOf(1)) {
- switch (la.kind) {
- case 59: case 60: case 62: {
- SubModuleDecl(defaultModule, out submodule);
- defaultModule.TopLevelDecls.Add(submodule);
- break;
- }
- case 67: {
- ClassDecl(defaultModule, out c);
- defaultModule.TopLevelDecls.Add(c);
- break;
- }
- case 73: case 74: {
- DatatypeDecl(defaultModule, out dt);
- defaultModule.TopLevelDecls.Add(dt);
- break;
- }
- case 76: {
- NewtypeDecl(defaultModule, out td);
- defaultModule.TopLevelDecls.Add(td);
- break;
- }
- case 77: {
- OtherTypeDecl(defaultModule, out td);
- defaultModule.TopLevelDecls.Add(td);
- break;
- }
- case 78: {
- IteratorDecl(defaultModule, out iter);
- defaultModule.TopLevelDecls.Add(iter);
- break;
- }
- case 69: {
- TraitDecl(defaultModule, out trait);
- defaultModule.TopLevelDecls.Add(trait);
- break;
- }
- case 36: case 37: case 38: case 39: case 40: case 70: case 71: case 72: case 75: case 81: case 82: case 83: case 84: {
- ClassMemberDecl(membersDefaultClass, false, !DafnyOptions.O.AllowGlobals);
- break;
- }
- }
+ TopDecl(defaultModule, membersDefaultClass, /* isTopLevel */ true, /* isAbstract */ false);
}
DefaultClassDecl defaultClass = null;
foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
@@ -591,106 +695,162 @@ bool IsType(ref IToken pt) {
Expect(0);
}
- void SubModuleDecl(ModuleDefinition parent, out ModuleDecl submodule) {
+ void TopDecl(ModuleDefinition module, List<MemberDecl/*!*/> membersDefaultClass, bool isTopLevel, bool isAbstract ) {
+ DeclModifierData dmod = new DeclModifierData(); ModuleDecl submodule;
ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;
- Attributes attrs = null; IToken/*!*/ id;
TraitDecl/*!*/ trait;
+
+ while (StartOf(2)) {
+ DeclModifier(ref dmod);
+ }
+ switch (la.kind) {
+ case 66: case 69: case 73: case 74: {
+ SubModuleDecl(dmod, module, out submodule);
+ module.TopLevelDecls.Add(submodule);
+ break;
+ }
+ case 77: {
+ ClassDecl(dmod, module, out c);
+ module.TopLevelDecls.Add(c);
+ break;
+ }
+ case 79: case 80: {
+ DatatypeDecl(dmod, module, out dt);
+ module.TopLevelDecls.Add(dt);
+ break;
+ }
+ case 82: {
+ NewtypeDecl(dmod, module, out td);
+ module.TopLevelDecls.Add(td);
+ break;
+ }
+ case 83: {
+ OtherTypeDecl(dmod, module, out td);
+ module.TopLevelDecls.Add(td);
+ break;
+ }
+ case 84: {
+ IteratorDecl(dmod, module, out iter);
+ module.TopLevelDecls.Add(iter);
+ break;
+ }
+ case 78: {
+ TraitDecl(dmod, module, out trait);
+ module.TopLevelDecls.Add(trait);
+ break;
+ }
+ case 38: case 39: case 40: case 41: case 42: case 81: case 87: case 88: case 89: case 90: {
+ ClassMemberDecl(dmod, membersDefaultClass, false, !DafnyOptions.O.AllowGlobals,
+!isTopLevel && DafnyOptions.O.IronDafny && isAbstract);
+ break;
+ }
+ default: SynErr(141); break;
+ }
+ }
+
+ void DeclModifier(ref DeclModifierData dmod) {
+ if (la.kind == 61) {
+ Get();
+ dmod.IsAbstract = true; CheckAndSetToken(ref dmod.AbstractToken);
+ } else if (la.kind == 62) {
+ Get();
+ dmod.IsGhost = true; CheckAndSetToken(ref dmod.GhostToken);
+ } else if (la.kind == 63) {
+ Get();
+ dmod.IsStatic = true; CheckAndSetToken(ref dmod.StaticToken);
+ } else if (la.kind == 64) {
+ Get();
+ dmod.IsProtected = true; CheckAndSetToken(ref dmod.ProtectedToken);
+ } else if (la.kind == 65) {
+ Get();
+ dmod.IsExtern = true; CheckAndSetToken(ref dmod.ExternToken);
+ if (la.kind == 20) {
+ Get();
+ bool isVerbatimString;
+ string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);
+ dmod.ExternName = new StringLiteralExpr(t, s, isVerbatimString);
+
+ }
+ } else SynErr(142);
+ }
+
+ void SubModuleDecl(DeclModifierData dmod, ModuleDefinition parent, out ModuleDecl submodule) {
+ Attributes attrs = null; IToken/*!*/ id;
List<MemberDecl/*!*/> namedModuleDefaultClassMembers = new List<MemberDecl>();;
List<IToken> idRefined = null, idPath = null, idAssignment = null;
ModuleDefinition module;
- ModuleDecl sm;
submodule = null; // appease compiler
- bool isAbstract = false;
+ bool isAbstract = dmod.IsAbstract;
+ bool isExclusively = false;
bool opened = false;
+ CheckDeclModifiers(dmod, "Modules", AllowedDeclModifiers.Abstract | AllowedDeclModifiers.Extern);
- if (la.kind == 59 || la.kind == 60) {
- if (la.kind == 59) {
- Get();
- isAbstract = true;
- }
- Expect(60);
- while (la.kind == 44) {
+ if (la.kind == 66) {
+ Get();
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 61) {
- Get();
- QualifiedModuleName(out idRefined);
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false);
+ if (la.kind == 67 || la.kind == 68) {
+ if (la.kind == 67) {
+ Get();
+ Expect(68);
+ QualifiedModuleName(out idRefined);
+ isExclusively = true;
+ } else {
+ Get();
+ QualifiedModuleName(out idRefined);
+ isExclusively = false;
+ }
}
- module = new ModuleDefinition(id, id.val, isAbstract, false, idRefined == null ? null : idRefined, parent, attrs, false);
- Expect(44);
+ module = new ModuleDefinition(id, id.val, isAbstract, false, isExclusively, idRefined == null ? null : idRefined, parent, attrs, false, this);
+ Expect(46);
module.BodyStartTok = t;
while (StartOf(1)) {
- switch (la.kind) {
- case 59: case 60: case 62: {
- SubModuleDecl(module, out sm);
- module.TopLevelDecls.Add(sm);
- break;
- }
- case 67: {
- ClassDecl(module, out c);
- module.TopLevelDecls.Add(c);
- break;
- }
- case 69: {
- TraitDecl(module, out trait);
- module.TopLevelDecls.Add(trait);
- break;
- }
- case 73: case 74: {
- DatatypeDecl(module, out dt);
- module.TopLevelDecls.Add(dt);
- break;
- }
- case 76: {
- NewtypeDecl(module, out td);
- module.TopLevelDecls.Add(td);
- break;
- }
- case 77: {
- OtherTypeDecl(module, out td);
- module.TopLevelDecls.Add(td);
- break;
- }
- case 78: {
- IteratorDecl(module, out iter);
- module.TopLevelDecls.Add(iter);
- break;
- }
- case 36: case 37: case 38: case 39: case 40: case 70: case 71: case 72: case 75: case 81: case 82: case 83: case 84: {
- ClassMemberDecl(namedModuleDefaultClassMembers, false, !DafnyOptions.O.AllowGlobals);
- break;
- }
- }
+ TopDecl(module, namedModuleDefaultClassMembers, /* isTopLevel */ false, isAbstract);
}
- Expect(45);
+ Expect(47);
module.BodyEndTok = t;
module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
submodule = new LiteralModuleDecl(module, parent);
- } else if (la.kind == 62) {
+ } else if (la.kind == 69) {
Get();
- if (la.kind == 63) {
+ if (la.kind == 70) {
Get();
opened = true;
}
NoUSIdent(out id);
- if (la.kind == 64 || la.kind == 65) {
- if (la.kind == 64) {
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false);
+ if (StartOf(3)) {
+ if (la.kind == 71) {
Get();
QualifiedModuleName(out idPath);
submodule = new AliasModuleDecl(idPath, id, parent, opened);
- } else {
+ } else if (la.kind == 72) {
Get();
QualifiedModuleName(out idPath);
- if (la.kind == 66) {
- Get();
+ if (IsDefaultImport()) {
+ Expect(73);
QualifiedModuleName(out idAssignment);
}
submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened);
+ errors.Warning(t, "\"import A as B\" has been deprecated; in the new syntax, it is \"import A:B\"");
+
+ } else if (la.kind == 21) {
+ Get();
+ QualifiedModuleName(out idPath);
+ submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened);
+ } else {
+ Get();
+ QualifiedModuleName(out idPath);
+ idPath.Insert(0, id);
+ submodule = new AliasModuleDecl(idPath, id, parent, opened);
+
}
}
- if (la.kind == 26) {
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(137); Get();}
+ if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(143); Get();}
Get();
errors.Warning(t, "the semi-colon that used to terminate a sub-module declaration has been deprecated; in the new syntax, just leave off the semi-colon");
}
@@ -700,10 +860,54 @@ bool IsType(ref IToken pt) {
submodule = new AliasModuleDecl(idPath, id, parent, opened);
}
- } else SynErr(138);
+ } else if (la.kind == 73 || la.kind == 74) {
+ bool isDefault = false;
+ bool includeBody;
+ IToken exportId;
+ List<ExportSignature> exports = new List<ExportSignature>();;
+ List<string> extends = new List<string>();
+
+ if (la.kind == 73) {
+ Get();
+ isDefault = true;
+ }
+ Expect(74);
+ NoUSIdent(out exportId);
+ if (la.kind == 75) {
+ Get();
+ NoUSIdent(out id);
+ extends.Add(id.val);
+ while (la.kind == 22) {
+ Get();
+ NoUSIdent(out id);
+ extends.Add(id.val);
+ }
+ }
+ Expect(46);
+ NoUSIdent(out id);
+ includeBody = false;
+ if (la.kind == 76) {
+ Get();
+ includeBody = true;
+ }
+ exports.Add(new ExportSignature(id, includeBody));
+ while (la.kind == 22) {
+ Get();
+ NoUSIdent(out id);
+ includeBody = false;
+ if (la.kind == 76) {
+ Get();
+ includeBody = true;
+ }
+ exports.Add(new ExportSignature(id, includeBody));
+ }
+ Expect(47);
+ submodule = new ModuleExportDecl(exportId, parent, isDefault, exports, extends);
+
+ } else SynErr(144);
}
- void ClassDecl(ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c) {
+ void ClassDecl(DeclModifierData dmodClass, ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c) {
Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out c) != null);
IToken/*!*/ id;
@@ -713,39 +917,46 @@ bool IsType(ref IToken pt) {
List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>();
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
+ CheckDeclModifiers(dmodClass, "Classes", AllowedDeclModifiers.Extern);
+ DeclModifierData dmod;
- while (!(la.kind == 0 || la.kind == 67)) {SynErr(139); Get();}
- Expect(67);
- while (la.kind == 44) {
+ while (!(la.kind == 0 || la.kind == 77)) {SynErr(145); Get();}
+ Expect(77);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 50) {
+ EncodeExternAsAttribute(dmodClass, ref attrs, id, /* needAxiom */ false);
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- if (la.kind == 68) {
+ if (la.kind == 75) {
Get();
Type(out trait);
traits.Add(trait);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Type(out trait);
traits.Add(trait);
}
}
- Expect(44);
+ Expect(46);
bodyStart = t;
- while (StartOf(2)) {
- ClassMemberDecl(members, true, false);
+ while (StartOf(4)) {
+ dmod = new DeclModifierData();
+ while (StartOf(2)) {
+ DeclModifier(ref dmod);
+ }
+ ClassMemberDecl(dmod, members, true, false, false);
}
- Expect(45);
+ Expect(47);
c = new ClassDecl(id, id.val, module, typeArgs, members, attrs, traits);
c.BodyStartTok = bodyStart;
c.BodyEndTok = t;
}
- void DatatypeDecl(ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt) {
+ void DatatypeDecl(DeclModifierData dmod, ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt) {
Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out dt)!=null);
IToken/*!*/ id;
@@ -754,30 +965,31 @@ bool IsType(ref IToken pt) {
List<DatatypeCtor/*!*/> ctors = new List<DatatypeCtor/*!*/>();
IToken bodyStart = Token.NoToken; // dummy assignment
bool co = false;
+ CheckDeclModifiers(dmod, "Datatypes or codatatypes", AllowedDeclModifiers.None);
- while (!(la.kind == 0 || la.kind == 73 || la.kind == 74)) {SynErr(140); Get();}
- if (la.kind == 73) {
+ while (!(la.kind == 0 || la.kind == 79 || la.kind == 80)) {SynErr(146); Get();}
+ if (la.kind == 79) {
Get();
- } else if (la.kind == 74) {
+ } else if (la.kind == 80) {
Get();
co = true;
- } else SynErr(141);
- while (la.kind == 44) {
+ } else SynErr(147);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- Expect(64);
+ Expect(71);
bodyStart = t;
DatatypeMemberDecl(ctors);
- while (la.kind == 22) {
+ while (la.kind == 23) {
Get();
DatatypeMemberDecl(ctors);
}
- if (la.kind == 26) {
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(142); Get();}
+ if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(148); Get();}
Get();
errors.Warning(t, "the semi-colon that used to terminate a (co)datatype declaration has been deprecated; in the new syntax, just leave off the semi-colon");
}
@@ -791,78 +1003,80 @@ bool IsType(ref IToken pt) {
}
- void NewtypeDecl(ModuleDefinition module, out TopLevelDecl td) {
+ void NewtypeDecl(DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td) {
IToken id, bvId;
Attributes attrs = null;
td = null;
Type baseType = null;
Expression wh;
+ CheckDeclModifiers(dmod, "Newtypes", AllowedDeclModifiers.None);
- Expect(76);
- while (la.kind == 44) {
+ Expect(82);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- Expect(64);
+ Expect(71);
if (IsIdentColonOrBar()) {
NoUSIdent(out bvId);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
Type(out baseType);
}
- if (baseType == null) { baseType = new OperationTypeProxy(true, true, false, false, false); }
- Expect(22);
+ if (baseType == null) { baseType = new OperationTypeProxy(true, true, false, false, false, false); }
+ Expect(23);
Expression(out wh, false, true);
td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, new BoundVar(bvId, bvId.val, baseType), wh, attrs);
- } else if (StartOf(3)) {
+ } else if (StartOf(5)) {
Type(out baseType);
td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, baseType, attrs);
- } else SynErr(143);
+ } else SynErr(149);
}
- void OtherTypeDecl(ModuleDefinition module, out TopLevelDecl td) {
+ void OtherTypeDecl(DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td) {
IToken id;
Attributes attrs = null;
var eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
var typeArgs = new List<TypeParameter>();
td = null;
Type ty;
+ CheckDeclModifiers(dmod, "Type aliases", AllowedDeclModifiers.None);
- Expect(77);
- while (la.kind == 44) {
+ Expect(83);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48) {
+ if (la.kind == 50) {
Get();
- Expect(52);
- Expect(49);
+ Expect(54);
+ Expect(51);
eqSupport = TypeParameter.EqualitySupportValue.Required;
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- } else if (StartOf(4)) {
- if (la.kind == 50) {
+ } else if (StartOf(6)) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- if (la.kind == 64) {
+ if (la.kind == 71) {
Get();
Type(out ty);
td = new TypeSynonymDecl(id, id.val, typeArgs, module, ty, attrs);
}
- } else SynErr(144);
+ } else SynErr(150);
if (td == null) {
td = new OpaqueTypeDecl(id, id.val, module, eqSupport, typeArgs, attrs);
}
- if (la.kind == 26) {
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(145); Get();}
+ if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(151); Get();}
Get();
errors.Warning(t, "the semi-colon that used to terminate an opaque-type declaration has been deprecated; in the new syntax, just leave off the semi-colon");
}
}
- void IteratorDecl(ModuleDefinition module, out IteratorDecl/*!*/ iter) {
+ void IteratorDecl(DeclModifierData dmod, ModuleDefinition module, out IteratorDecl/*!*/ iter) {
Contract.Ensures(Contract.ValueAtReturn(out iter) != null);
IToken/*!*/ id;
Attributes attrs = null;
@@ -884,20 +1098,21 @@ bool IsType(ref IToken pt) {
IToken signatureEllipsis = null;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ CheckDeclModifiers(dmod, "Iterators", AllowedDeclModifiers.None);
- while (!(la.kind == 0 || la.kind == 78)) {SynErr(146); Get();}
- Expect(78);
- while (la.kind == 44) {
+ while (!(la.kind == 0 || la.kind == 84)) {SynErr(152); Get();}
+ Expect(84);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48 || la.kind == 50) {
- if (la.kind == 50) {
+ if (la.kind == 50 || la.kind == 52) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
Formals(true, true, ins);
- if (la.kind == 79 || la.kind == 80) {
- if (la.kind == 79) {
+ if (la.kind == 85 || la.kind == 86) {
+ if (la.kind == 85) {
Get();
} else {
Get();
@@ -905,14 +1120,14 @@ bool IsType(ref IToken pt) {
}
Formals(false, true, outs);
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(147);
- while (StartOf(5)) {
+ } else SynErr(153);
+ while (StartOf(7)) {
IteratorSpec(reads, mod, decreases, req, ens, yieldReq, yieldEns, ref readsAttrs, ref modAttrs, ref decrAttrs);
}
- if (la.kind == 44) {
+ if (la.kind == 46) {
BlockStmt(out body, out bodyStart, out bodyEnd);
}
iter = new IteratorDecl(id, id.val, module, typeArgs, ins, outs,
@@ -926,98 +1141,85 @@ bool IsType(ref IToken pt) {
}
- void TraitDecl(ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait) {
- Contract.Requires(module != null);
+ void TraitDecl(DeclModifierData dmodIn, ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait) {
+ Contract.Requires(module != null);
Contract.Ensures(Contract.ValueAtReturn(out trait) != null);
+ CheckDeclModifiers(dmodIn, "Traits", AllowedDeclModifiers.None);
IToken/*!*/ id;
Attributes attrs = null;
List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>(); //traits should not support type parameters at the moment
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
+ DeclModifierData dmod;
- while (!(la.kind == 0 || la.kind == 69)) {SynErr(148); Get();}
- Expect(69);
- while (la.kind == 44) {
+ while (!(la.kind == 0 || la.kind == 78)) {SynErr(154); Get();}
+ Expect(78);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- Expect(44);
+ Expect(46);
bodyStart = t;
- while (StartOf(2)) {
- ClassMemberDecl(members, true, false);
+ while (StartOf(4)) {
+ dmod = new DeclModifierData();
+ while (StartOf(2)) {
+ DeclModifier(ref dmod);
+ }
+ ClassMemberDecl(dmod, members, true, false, false);
}
- Expect(45);
+ Expect(47);
trait = new TraitDecl(id, id.val, module, typeArgs, members, attrs);
trait.BodyStartTok = bodyStart;
trait.BodyEndTok = t;
}
- void ClassMemberDecl(List<MemberDecl> mm, bool allowConstructors, bool moduleLevelDecl) {
+ void ClassMemberDecl(DeclModifierData dmod, List<MemberDecl> mm, bool allowConstructors, bool moduleLevelDecl, bool isWithinAbstractModule) {
Contract.Requires(cce.NonNullElements(mm));
Method/*!*/ m;
Function/*!*/ f;
- MemberModifiers mmod = new MemberModifiers();
- IToken staticToken = null, protectedToken = null;
- while (la.kind == 70 || la.kind == 71 || la.kind == 72) {
- if (la.kind == 70) {
- Get();
- mmod.IsGhost = true;
- } else if (la.kind == 71) {
- Get();
- mmod.IsStatic = true; staticToken = t;
- } else {
- Get();
- mmod.IsProtected = true; protectedToken = t;
- }
- }
- if (la.kind == 75) {
+ if (la.kind == 81) {
if (moduleLevelDecl) {
SemErr(la, "fields are not allowed to be declared at the module level; instead, wrap the field in a 'class' declaration");
- mmod.IsStatic = false;
- mmod.IsProtected = false;
+ dmod.IsStatic = false;
}
- FieldDecl(mmod, mm);
+ FieldDecl(dmod, mm);
} else if (IsFunctionDecl()) {
- if (moduleLevelDecl && staticToken != null) {
- errors.Warning(staticToken, "module-level functions are always non-instance, so the 'static' keyword is not allowed here");
- mmod.IsStatic = false;
+ if (moduleLevelDecl && dmod.StaticToken != null) {
+ errors.Warning(dmod.StaticToken, "module-level functions are always non-instance, so the 'static' keyword is not allowed here");
+ dmod.IsStatic = false;
}
- FunctionDecl(mmod, out f);
+ FunctionDecl(dmod, isWithinAbstractModule, out f);
mm.Add(f);
- } else if (StartOf(6)) {
- if (moduleLevelDecl && staticToken != null) {
- errors.Warning(staticToken, "module-level methods are always non-instance, so the 'static' keyword is not allowed here");
- mmod.IsStatic = false;
- }
- if (protectedToken != null) {
- SemErr(protectedToken, "only functions, not methods, can be declared 'protected'");
- mmod.IsProtected = false;
+ } else if (StartOf(8)) {
+ if (moduleLevelDecl && dmod.StaticToken != null) {
+ errors.Warning(dmod.StaticToken, "module-level methods are always non-instance, so the 'static' keyword is not allowed here");
+ dmod.IsStatic = false;
}
- MethodDecl(mmod, allowConstructors, out m);
+ MethodDecl(dmod, allowConstructors, isWithinAbstractModule, out m);
mm.Add(m);
- } else SynErr(149);
+ } else SynErr(155);
}
void Attribute(ref Attributes attrs) {
- string name;
+ IToken x; string name;
var args = new List<Expression>();
- Expect(44);
- Expect(20);
- Expect(1);
- name = t.val;
- if (StartOf(7)) {
+ Expect(46);
+ Expect(21);
+ NoUSIdent(out x);
+ name = x.val;
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(45);
+ Expect(47);
attrs = new Attributes(name, args, attrs);
}
@@ -1035,7 +1237,7 @@ bool IsType(ref IToken pt) {
IToken id; ids = new List<IToken>();
Ident(out id);
ids.Add(id);
- while (la.kind == 25) {
+ while (la.kind == 27) {
Get();
Ident(out id);
ids.Add(id);
@@ -1053,29 +1255,29 @@ bool IsType(ref IToken pt) {
IToken/*!*/ id;
TypeParameter.EqualitySupportValue eqSupport;
- Expect(50);
+ Expect(52);
NoUSIdent(out id);
eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
- if (la.kind == 48) {
+ if (la.kind == 50) {
Get();
- Expect(52);
- Expect(49);
+ Expect(54);
+ Expect(51);
eqSupport = TypeParameter.EqualitySupportValue.Required;
}
typeArgs.Add(new TypeParameter(id, id.val, eqSupport));
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
NoUSIdent(out id);
eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
- if (la.kind == 48) {
+ if (la.kind == 50) {
Get();
- Expect(52);
- Expect(49);
+ Expect(54);
+ Expect(51);
eqSupport = TypeParameter.EqualitySupportValue.Required;
}
typeArgs.Add(new TypeParameter(id, id.val, eqSupport));
}
- Expect(51);
+ Expect(53);
}
void Type(out Type ty) {
@@ -1083,29 +1285,28 @@ bool IsType(ref IToken pt) {
TypeAndToken(out tok, out ty);
}
- void FieldDecl(MemberModifiers mmod, List<MemberDecl/*!*/>/*!*/ mm) {
+ void FieldDecl(DeclModifierData dmod, List<MemberDecl/*!*/>/*!*/ mm) {
Contract.Requires(cce.NonNullElements(mm));
Attributes attrs = null;
IToken/*!*/ id; Type/*!*/ ty;
+ CheckDeclModifiers(dmod, "Fields", AllowedDeclModifiers.Ghost);
- while (!(la.kind == 0 || la.kind == 75)) {SynErr(150); Get();}
- Expect(75);
- if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); }
-
- while (la.kind == 44) {
+ while (!(la.kind == 0 || la.kind == 81)) {SynErr(156); Get();}
+ Expect(81);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
FIdentType(out id, out ty);
- mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs));
- while (la.kind == 21) {
+ mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs));
+ while (la.kind == 22) {
Get();
FIdentType(out id, out ty);
- mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs));
+ mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs));
}
OldSemi();
}
- void FunctionDecl(MemberModifiers mmod, out Function/*!*/ f) {
+ void FunctionDecl(DeclModifierData dmod, bool isWithinAbstractModule, out Function/*!*/ f) {
Contract.Ensures(Contract.ValueAtReturn(out f)!=null);
Attributes attrs = null;
IToken/*!*/ id = Token.NoToken; // to please compiler
@@ -1124,129 +1325,144 @@ bool IsType(ref IToken pt) {
IToken signatureEllipsis = null;
bool missingOpenParen;
- if (la.kind == 36) {
+ if (la.kind == 38) {
Get();
- if (la.kind == 81) {
+ if (la.kind == 87) {
Get();
isFunctionMethod = true;
}
- if (mmod.IsGhost) { SemErr(t, "functions cannot be declared 'ghost' (they are ghost by default)"); }
+ AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected;
+ string caption = "Functions";
+ if (isFunctionMethod) {
+ allowed |= AllowedDeclModifiers.Extern;
+ caption = "Function methods";
+ }
+ CheckDeclModifiers(dmod, caption, allowed);
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48 || la.kind == 50) {
- if (la.kind == 50) {
+ if (la.kind == 50 || la.kind == 52) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
Formals(true, isFunctionMethod, formals);
- Expect(20);
+ Expect(21);
Type(out returnType);
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(151);
- } else if (la.kind == 37) {
+ } else SynErr(157);
+ } else if (la.kind == 39) {
Get();
isPredicate = true;
- if (la.kind == 81) {
+ if (la.kind == 87) {
Get();
isFunctionMethod = true;
}
- if (mmod.IsGhost) { SemErr(t, "predicates cannot be declared 'ghost' (they are ghost by default)"); }
+ AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected;
+ string caption = "Predicates";
+ if (isFunctionMethod) {
+ allowed |= AllowedDeclModifiers.Extern;
+ caption = "Predicate methods";
+ }
+ CheckDeclModifiers(dmod, caption, allowed);
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (StartOf(8)) {
- if (la.kind == 50) {
+ if (StartOf(10)) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
missingOpenParen = true;
- if (la.kind == 48) {
+ if (la.kind == 50) {
Formals(true, isFunctionMethod, formals);
missingOpenParen = false;
}
if (missingOpenParen) { errors.Warning(t, "with the new support of higher-order functions in Dafny, parentheses-less predicates are no longer supported; in the new syntax, parentheses are required for the declaration and uses of predicates, even if the predicate takes no additional arguments"); }
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
SemErr(t, "predicates do not have an explicitly declared return type; it is always bool");
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(152);
- } else if (la.kind == 38) {
+ } else SynErr(158);
+ } else if (la.kind == 40) {
Get();
- Expect(37);
+ Expect(39);
isIndPredicate = true;
- if (mmod.IsGhost) { SemErr(t, "inductive predicates cannot be declared 'ghost' (they are ghost by default)"); }
+ CheckDeclModifiers(dmod, "Inductive predicates",
+ AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48 || la.kind == 50) {
- if (la.kind == 50) {
+ if (la.kind == 50 || la.kind == 52) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
Formals(true, isFunctionMethod, formals);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
SemErr(t, "inductive predicates do not have an explicitly declared return type; it is always bool");
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(153);
- } else if (la.kind == 40) {
+ } else SynErr(159);
+ } else if (la.kind == 42) {
Get();
isCoPredicate = true;
- if (mmod.IsGhost) { SemErr(t, "copredicates cannot be declared 'ghost' (they are ghost by default)"); }
+ CheckDeclModifiers(dmod, "Copredicates",
+ AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48 || la.kind == 50) {
- if (la.kind == 50) {
+ if (la.kind == 50 || la.kind == 52) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
Formals(true, isFunctionMethod, formals);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
SemErr(t, "copredicates do not have an explicitly declared return type; it is always bool");
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(154);
- } else SynErr(155);
+ } else SynErr(160);
+ } else SynErr(161);
decreases = isIndPredicate || isCoPredicate ? null : new List<Expression/*!*/>();
- while (StartOf(9)) {
+ while (StartOf(11)) {
FunctionSpec(reqs, reads, ens, decreases);
}
- if (la.kind == 44) {
+ if (la.kind == 46) {
FunctionBody(out body, out bodyStart, out bodyEnd);
}
- if (DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported")) {
+ if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 &&
+ !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported")) {
SemErr(t, "a function with an ensures clause must have a body, unless given the :axiom attribute");
}
-
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true);
IToken tok = theVerifyThisFile ? id : new IncludeToken(id);
if (isPredicate) {
- f = new Predicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, !isFunctionMethod, typeArgs, formals,
+ f = new Predicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureEllipsis);
} else if (isIndPredicate) {
- f = new InductivePredicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, typeArgs, formals,
+ f = new InductivePredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals,
reqs, reads, ens, body, attrs, signatureEllipsis);
} else if (isCoPredicate) {
- f = new CoPredicate(tok, id.val, mmod.IsStatic, mmod.IsProtected, typeArgs, formals,
+ f = new CoPredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals,
reqs, reads, ens, body, attrs, signatureEllipsis);
} else {
- f = new Function(tok, id.val, mmod.IsStatic, mmod.IsProtected, !isFunctionMethod, typeArgs, formals, returnType,
+ f = new Function(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals, returnType,
reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);
}
f.BodyStartTok = bodyStart;
@@ -1259,7 +1475,7 @@ bool IsType(ref IToken pt) {
}
- void MethodDecl(MemberModifiers mmod, bool allowConstructor, out Method/*!*/ m) {
+ void MethodDecl(DeclModifierData dmod, bool allowConstructor, bool isWithinAbstractModule, out Method/*!*/ m) {
Contract.Ensures(Contract.ValueAtReturn(out m) !=null);
IToken/*!*/ id = Token.NoToken;
bool hasName = false; IToken keywordToken;
@@ -1281,71 +1497,65 @@ bool IsType(ref IToken pt) {
IToken signatureEllipsis = null;
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
+ AllowedDeclModifiers allowed = AllowedDeclModifiers.None;
+ string caption = "";
- while (!(StartOf(10))) {SynErr(156); Get();}
+ while (!(StartOf(12))) {SynErr(162); Get();}
switch (la.kind) {
- case 81: {
+ case 87: {
Get();
+ caption = "Methods";
+ allowed = AllowedDeclModifiers.Ghost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Extern;
break;
}
- case 39: {
+ case 41: {
Get();
- isLemma = true;
+ isLemma = true; caption = "Lemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected;
break;
}
- case 82: {
+ case 88: {
Get();
- isCoLemma = true;
+ isCoLemma = true; caption = "Colemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected;
break;
}
- case 83: {
+ case 89: {
Get();
- isCoLemma = true;
+ isCoLemma = true; caption = "Comethods";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static
+ | AllowedDeclModifiers.Protected;
errors.Warning(t, "the 'comethod' keyword has been deprecated; it has been renamed to 'colemma'");
break;
}
- case 38: {
+ case 40: {
Get();
- Expect(39);
- isIndLemma = true;
+ Expect(41);
+ isIndLemma = true; caption = "Inductive lemmas";
+ allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static;
break;
}
- case 84: {
+ case 90: {
Get();
if (allowConstructor) {
isConstructor = true;
} else {
SemErr(t, "constructors are allowed only in classes");
- }
+ }
+ caption = "Constructors";
+ allowed = AllowedDeclModifiers.None;
break;
}
- default: SynErr(157); break;
+ default: SynErr(163); break;
}
keywordToken = t;
- if (isLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "lemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- } else if (isConstructor) {
- if (mmod.IsGhost) {
- SemErr(t, "constructors cannot be declared 'ghost'");
- }
- if (mmod.IsStatic) {
- SemErr(t, "constructors cannot be declared 'static'");
- }
- } else if (isIndLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "inductive lemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- } else if (isCoLemma) {
- if (mmod.IsGhost) {
- SemErr(t, "colemmas cannot be declared 'ghost' (they are automatically 'ghost')");
- }
- }
-
- while (la.kind == 44) {
+ CheckDeclModifiers(dmod, caption, allowed);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
if (la.kind == 1) {
@@ -1358,28 +1568,29 @@ bool IsType(ref IToken pt) {
SemErr(la, "a method must be given a name (expecting identifier)");
}
}
+ EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true);
- if (la.kind == 48 || la.kind == 50) {
- if (la.kind == 50) {
+ if (la.kind == 50 || la.kind == 52) {
+ if (la.kind == 52) {
GenericParameters(typeArgs);
}
- Formals(true, !mmod.IsGhost, ins);
- if (la.kind == 80) {
+ Formals(true, !dmod.IsGhost, ins);
+ if (la.kind == 86) {
Get();
if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); }
- Formals(false, !mmod.IsGhost, outs);
+ Formals(false, !dmod.IsGhost, outs);
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
signatureEllipsis = t;
- } else SynErr(158);
- while (StartOf(11)) {
+ } else SynErr(164);
+ while (StartOf(13)) {
MethodSpec(req, mod, ens, dec, ref decAttrs, ref modAttrs);
}
- if (la.kind == 44) {
+ if (la.kind == 46) {
BlockStmt(out body, out bodyStart, out bodyEnd);
}
- if (DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported") && !Attributes.Contains(attrs, "decl") && theVerifyThisFile) {
+ if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported") && !Attributes.Contains(attrs, "decl") && theVerifyThisFile) {
SemErr(t, "a method with an ensures clause must have a body, unless given the :axiom attribute");
}
@@ -1388,16 +1599,16 @@ bool IsType(ref IToken pt) {
m = new Constructor(tok, hasName ? id.val : "_ctor", typeArgs, ins,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isIndLemma) {
- m = new InductiveLemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new InductiveLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isCoLemma) {
- m = new CoLemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new CoLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else if (isLemma) {
- m = new Lemma(tok, id.val, mmod.IsStatic, typeArgs, ins, outs,
+ m = new Lemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
} else {
- m = new Method(tok, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs,
+ m = new Method(tok, id.val, dmod.IsStatic, dmod.IsGhost, typeArgs, ins, outs,
req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);
}
m.BodyStartTok = bodyStart;
@@ -1411,11 +1622,11 @@ bool IsType(ref IToken pt) {
IToken/*!*/ id;
List<Formal/*!*/> formals = new List<Formal/*!*/>();
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 48) {
+ if (la.kind == 50) {
FormalsOptionalIds(formals);
}
ctors.Add(new DatatypeCtor(id, id.val, formals, attrs));
@@ -1423,17 +1634,17 @@ bool IsType(ref IToken pt) {
void FormalsOptionalIds(List<Formal/*!*/>/*!*/ formals) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost;
- Expect(48);
- if (StartOf(12)) {
+ Expect(50);
+ if (StartOf(14)) {
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
}
}
- Expect(49);
+ Expect(51);
}
void FIdentType(out IToken/*!*/ id, out Type/*!*/ ty) {
@@ -1445,14 +1656,14 @@ bool IsType(ref IToken pt) {
} else if (la.kind == 2) {
Get();
id = t;
- } else SynErr(159);
- Expect(20);
+ } else SynErr(165);
+ Expect(21);
Type(out ty);
}
void OldSemi() {
- if (la.kind == 26) {
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(160); Get();}
+ if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(166); Get();}
Get();
}
}
@@ -1461,7 +1672,7 @@ bool IsType(ref IToken pt) {
Expression e0; IToken endTok;
EquivExpression(out e, allowSemi, allowLambda);
if (SemiFollowsCall(allowSemi, e)) {
- Expect(26);
+ Expect(28);
endTok = t;
Expression(out e0, allowSemi, allowLambda);
e = new StmtExpr(e.tok,
@@ -1475,7 +1686,7 @@ bool IsType(ref IToken pt) {
Contract.Ensures(Contract.ValueAtReturn(out id)!=null);
Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);
isGhost = false;
- if (la.kind == 70) {
+ if (la.kind == 62) {
Get();
if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); }
}
@@ -1485,7 +1696,7 @@ bool IsType(ref IToken pt) {
void IdentType(out IToken/*!*/ id, out Type/*!*/ ty, bool allowWildcardId) {
Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);
WildIdent(out id, allowWildcardId);
- Expect(20);
+ Expect(21);
Type(out ty);
}
@@ -1501,7 +1712,7 @@ bool IsType(ref IToken pt) {
IToken id; Type ty; Type optType = null;
WildIdent(out id, true);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
Type(out ty);
optType = ty;
@@ -1514,7 +1725,7 @@ bool IsType(ref IToken pt) {
IToken id; Type ty; Type optType = null;
WildIdent(out id, true);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
Type(out ty);
optType = ty;
@@ -1527,13 +1738,13 @@ bool IsType(ref IToken pt) {
Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);
Contract.Ensures(Contract.ValueAtReturn(out identName)!=null);
string name = null; id = Token.NoToken; ty = new BoolType()/*dummy*/; isGhost = false;
- if (la.kind == 70) {
+ if (la.kind == 62) {
Get();
isGhost = true;
}
- if (StartOf(3)) {
+ if (StartOf(5)) {
TypeAndToken(out id, out ty);
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
UserDefinedType udt = ty as UserDefinedType;
if (udt != null && udt.TypeArgs.Count == 0) {
@@ -1547,9 +1758,9 @@ bool IsType(ref IToken pt) {
} else if (la.kind == 2) {
Get();
id = t; name = id.val;
- Expect(20);
+ Expect(21);
Type(out ty);
- } else SynErr(161);
+ } else SynErr(167);
if (name != null) {
identName = name;
} else {
@@ -1597,20 +1808,33 @@ bool IsType(ref IToken pt) {
case 13: {
Get();
tok = t; gt = new List<Type>();
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericInstantiation(gt);
}
if (gt.Count > 1) {
SemErr("set type expects only one type argument");
}
- ty = new SetType(gt.Count == 1 ? gt[0] : null);
+ ty = new SetType(true, gt.Count == 1 ? gt[0] : null);
break;
}
case 14: {
Get();
tok = t; gt = new List<Type>();
- if (la.kind == 50) {
+ if (la.kind == 52) {
+ GenericInstantiation(gt);
+ }
+ if (gt.Count > 1) {
+ SemErr("set type expects only one type argument");
+ }
+ ty = new SetType(false, gt.Count == 1 ? gt[0] : null);
+
+ break;
+ }
+ case 15: {
+ Get();
+ tok = t; gt = new List<Type>();
+ if (la.kind == 52) {
GenericInstantiation(gt);
}
if (gt.Count > 1) {
@@ -1620,10 +1844,10 @@ bool IsType(ref IToken pt) {
break;
}
- case 15: {
+ case 16: {
Get();
tok = t; gt = new List<Type>();
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericInstantiation(gt);
}
if (gt.Count > 1) {
@@ -1638,10 +1862,10 @@ bool IsType(ref IToken pt) {
tok = t; ty = new UserDefinedType(tok, tok.val, null);
break;
}
- case 16: {
+ case 17: {
Get();
tok = t; gt = new List<Type>();
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericInstantiation(gt);
}
if (gt.Count == 0) {
@@ -1655,10 +1879,10 @@ bool IsType(ref IToken pt) {
break;
}
- case 17: {
+ case 18: {
Get();
tok = t; gt = new List<Type>();
- if (la.kind == 50) {
+ if (la.kind == 52) {
GenericInstantiation(gt);
}
if (gt.Count == 0) {
@@ -1675,7 +1899,7 @@ bool IsType(ref IToken pt) {
case 5: {
Get();
tok = t; gt = null;
- if (la.kind == 50) {
+ if (la.kind == 52) {
gt = new List<Type>();
GenericInstantiation(gt);
}
@@ -1684,19 +1908,19 @@ bool IsType(ref IToken pt) {
break;
}
- case 48: {
+ case 50: {
Get();
tok = t; tupleArgTypes = new List<Type>();
- if (StartOf(3)) {
+ if (StartOf(5)) {
Type(out ty);
tupleArgTypes.Add(ty);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Type(out ty);
tupleArgTypes.Add(ty);
}
}
- Expect(49);
+ Expect(51);
if (tupleArgTypes.Count == 1) {
// just return the type 'ty'
} else {
@@ -1711,11 +1935,11 @@ bool IsType(ref IToken pt) {
Expression e; tok = t;
NameSegmentForTypeName(out e);
tok = t;
- while (la.kind == 25) {
+ while (la.kind == 27) {
Get();
Expect(1);
tok = t; List<Type> typeArgs = null;
- if (la.kind == 50) {
+ if (la.kind == 52) {
typeArgs = new List<Type>();
GenericInstantiation(typeArgs);
}
@@ -1724,9 +1948,9 @@ bool IsType(ref IToken pt) {
ty = new UserDefinedType(e.tok, e);
break;
}
- default: SynErr(162); break;
+ default: SynErr(168); break;
}
- if (la.kind == 28) {
+ if (la.kind == 30) {
Type t2;
Get();
tok = t;
@@ -1744,17 +1968,17 @@ bool IsType(ref IToken pt) {
void Formals(bool incoming, bool allowGhostKeyword, List<Formal> formals) {
Contract.Requires(cce.NonNullElements(formals)); IToken id; Type ty; bool isGhost;
- Expect(48);
- if (la.kind == 1 || la.kind == 70) {
+ Expect(50);
+ if (la.kind == 1 || la.kind == 62) {
GIdentType(allowGhostKeyword, out id, out ty, out isGhost);
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
GIdentType(allowGhostKeyword, out id, out ty, out isGhost);
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
}
}
- Expect(49);
+ Expect(51);
}
void IteratorSpec(List<FrameExpression/*!*/>/*!*/ reads, List<FrameExpression/*!*/>/*!*/ mod, List<Expression/*!*/> decreases,
@@ -1763,45 +1987,45 @@ List<MaybeFreeExpression/*!*/>/*!*/ yieldReq, List<MaybeFreeExpression/*!*/>/*!*
ref Attributes readsAttrs, ref Attributes modAttrs, ref Attributes decrAttrs) {
Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; bool isYield = false; Attributes ensAttrs = null;
- while (!(StartOf(13))) {SynErr(163); Get();}
- if (la.kind == 42) {
+ while (!(StartOf(15))) {SynErr(169); Get();}
+ if (la.kind == 44) {
Get();
while (IsAttribute()) {
Attribute(ref readsAttrs);
}
FrameExpression(out fe, false, false);
reads.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
FrameExpression(out fe, false, false);
reads.Add(fe);
}
OldSemi();
- } else if (la.kind == 41) {
+ } else if (la.kind == 43) {
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
}
FrameExpression(out fe, false, false);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
FrameExpression(out fe, false, false);
mod.Add(fe);
}
OldSemi();
- } else if (StartOf(14)) {
- if (la.kind == 85) {
+ } else if (StartOf(16)) {
+ if (la.kind == 91) {
Get();
isFree = true;
errors.Warning(t, "the 'free' keyword is soon to be deprecated");
}
- if (la.kind == 87) {
+ if (la.kind == 93) {
Get();
isYield = true;
}
- if (la.kind == 43) {
+ if (la.kind == 45) {
Get();
Expression(out e, false, false);
OldSemi();
@@ -1811,7 +2035,7 @@ ref Attributes readsAttrs, ref Attributes modAttrs, ref Attributes decrAttrs) {
req.Add(new MaybeFreeExpression(e, isFree));
}
- } else if (la.kind == 86) {
+ } else if (la.kind == 92) {
Get();
while (IsAttribute()) {
Attribute(ref ensAttrs);
@@ -1824,27 +2048,27 @@ ref Attributes readsAttrs, ref Attributes modAttrs, ref Attributes decrAttrs) {
ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));
}
- } else SynErr(164);
- } else if (la.kind == 34) {
+ } else SynErr(170);
+ } else if (la.kind == 36) {
Get();
while (IsAttribute()) {
Attribute(ref decrAttrs);
}
DecreasesList(decreases, false, false);
OldSemi();
- } else SynErr(165);
+ } else SynErr(171);
}
void BlockStmt(out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd) {
Contract.Ensures(Contract.ValueAtReturn(out block) != null);
List<Statement/*!*/> body = new List<Statement/*!*/>();
- Expect(44);
+ Expect(46);
bodyStart = t;
- while (StartOf(15)) {
+ while (StartOf(17)) {
Stmt(body);
}
- Expect(45);
+ Expect(47);
bodyEnd = t;
block = new BlockStmt(bodyStart, bodyEnd, body);
}
@@ -1854,33 +2078,33 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Requires(cce.NonNullElements(req)); Contract.Requires(cce.NonNullElements(mod)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; Attributes ensAttrs = null;
- while (!(StartOf(16))) {SynErr(166); Get();}
- if (la.kind == 41) {
+ while (!(StartOf(18))) {SynErr(172); Get();}
+ if (la.kind == 43) {
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
}
FrameExpression(out fe, false, false);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
FrameExpression(out fe, false, false);
mod.Add(fe);
}
OldSemi();
- } else if (la.kind == 43 || la.kind == 85 || la.kind == 86) {
- if (la.kind == 85) {
+ } else if (la.kind == 45 || la.kind == 91 || la.kind == 92) {
+ if (la.kind == 91) {
Get();
isFree = true;
errors.Warning(t, "the 'free' keyword is soon to be deprecated");
}
- if (la.kind == 43) {
+ if (la.kind == 45) {
Get();
Expression(out e, false, false);
OldSemi();
req.Add(new MaybeFreeExpression(e, isFree));
- } else if (la.kind == 86) {
+ } else if (la.kind == 92) {
Get();
while (IsAttribute()) {
Attribute(ref ensAttrs);
@@ -1888,15 +2112,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression(out e, false, false);
OldSemi();
ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));
- } else SynErr(167);
- } else if (la.kind == 34) {
+ } else SynErr(173);
+ } else if (la.kind == 36) {
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, true, false);
OldSemi();
- } else SynErr(168);
+ } else SynErr(174);
}
void FrameExpression(out FrameExpression fe, bool allowSemi, bool allowLambda) {
@@ -1906,21 +2130,21 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
string fieldName = null; IToken feTok = null;
fe = null;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out e, allowSemi, allowLambda);
feTok = e.tok;
- if (la.kind == 88) {
+ if (la.kind == 94) {
Get();
Ident(out id);
fieldName = id.val; feTok = id;
}
fe = new FrameExpression(feTok, e, fieldName);
- } else if (la.kind == 88) {
+ } else if (la.kind == 94) {
Get();
Ident(out id);
fieldName = id.val;
fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName);
- } else SynErr(169);
+ } else SynErr(175);
}
void DecreasesList(List<Expression> decreases, bool allowWildcard, bool allowLambda) {
@@ -1932,7 +2156,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
decreases.Add(e);
}
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
PossiblyWildExpression(out e, allowLambda);
if (!allowWildcard && e is WildcardExpr) {
@@ -1946,15 +2170,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void GenericInstantiation(List<Type/*!*/>/*!*/ gt) {
Contract.Requires(cce.NonNullElements(gt)); Type/*!*/ ty;
- Expect(50);
+ Expect(52);
Type(out ty);
gt.Add(ty);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Type(out ty);
gt.Add(ty);
}
- Expect(51);
+ Expect(53);
}
void NameSegmentForTypeName(out Expression e) {
@@ -1962,7 +2186,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Type> typeArgs = null;
Ident(out id);
- if (la.kind == 50) {
+ if (la.kind == 52) {
typeArgs = new List<Type>();
GenericInstantiation(typeArgs);
}
@@ -1975,28 +2199,28 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Requires(cce.NonNullElements(reads));
Contract.Requires(decreases == null || cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe;
- while (!(StartOf(17))) {SynErr(170); Get();}
- if (la.kind == 43) {
+ while (!(StartOf(19))) {SynErr(176); Get();}
+ if (la.kind == 45) {
Get();
Expression(out e, false, false);
OldSemi();
reqs.Add(e);
- } else if (la.kind == 42) {
+ } else if (la.kind == 44) {
Get();
PossiblyWildFrameExpression(out fe, false);
reads.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
PossiblyWildFrameExpression(out fe, false);
reads.Add(fe);
}
OldSemi();
- } else if (la.kind == 86) {
+ } else if (la.kind == 92) {
Get();
Expression(out e, false, false);
OldSemi();
ens.Add(e);
- } else if (la.kind == 34) {
+ } else if (la.kind == 36) {
Get();
if (decreases == null) {
SemErr(t, "'decreases' clauses are meaningless for copredicates, so they are not allowed");
@@ -2005,37 +2229,37 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
DecreasesList(decreases, false, false);
OldSemi();
- } else SynErr(171);
+ } else SynErr(177);
}
void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr;
- Expect(44);
+ Expect(46);
bodyStart = t;
Expression(out e, true, true);
- Expect(45);
+ Expect(47);
bodyEnd = t;
}
void PossiblyWildFrameExpression(out FrameExpression fe, bool allowSemi) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr;
- if (la.kind == 55) {
+ if (la.kind == 57) {
Get();
fe = new FrameExpression(t, new WildcardExpr(t), null);
- } else if (StartOf(18)) {
+ } else if (StartOf(20)) {
FrameExpression(out fe, allowSemi, false);
- } else SynErr(172);
+ } else SynErr(178);
}
void PossiblyWildExpression(out Expression e, bool allowLambda) {
Contract.Ensures(Contract.ValueAtReturn(out e)!=null);
e = dummyExpr;
- if (la.kind == 55) {
+ if (la.kind == 57) {
Get();
e = new WildcardExpr(t);
- } else if (StartOf(7)) {
+ } else if (StartOf(9)) {
Expression(out e, false, allowLambda);
- } else SynErr(173);
+ } else SynErr(179);
}
void Stmt(List<Statement/*!*/>/*!*/ ss) {
@@ -2052,92 +2276,92 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken bodyStart, bodyEnd;
int breakCount;
- while (!(StartOf(19))) {SynErr(174); Get();}
+ while (!(StartOf(21))) {SynErr(180); Get();}
switch (la.kind) {
- case 44: {
+ case 46: {
BlockStmt(out bs, out bodyStart, out bodyEnd);
s = bs;
break;
}
- case 99: {
+ case 104: {
AssertStmt(out s);
break;
}
- case 29: {
+ case 31: {
AssumeStmt(out s);
break;
}
- case 100: {
+ case 105: {
PrintStmt(out s);
break;
}
- case 1: case 2: case 3: case 4: case 8: case 10: case 18: case 19: case 22: case 48: case 129: case 130: case 131: case 132: case 133: case 134: {
+ case 1: case 2: case 3: case 4: case 8: case 10: case 19: case 20: case 23: case 50: case 133: case 134: case 135: case 136: case 137: case 138: {
UpdateStmt(out s);
break;
}
- case 70: case 75: {
+ case 62: case 81: {
VarDeclStatement(out s);
break;
}
- case 96: {
+ case 101: {
IfStmt(out s);
break;
}
- case 97: {
+ case 102: {
WhileStmt(out s);
break;
}
- case 98: {
+ case 103: {
MatchStmt(out s);
break;
}
- case 101: case 102: {
+ case 106: case 107: {
ForallStmt(out s);
break;
}
- case 30: {
+ case 32: {
CalcStmt(out s);
break;
}
- case 103: {
+ case 108: {
ModifyStmt(out s);
break;
}
- case 89: {
+ case 95: {
Get();
x = t;
NoUSIdent(out id);
- Expect(20);
+ Expect(21);
OneStmt(out s);
s.Labels = new LList<Label>(new Label(x, id.val), s.Labels);
break;
}
- case 90: {
+ case 96: {
Get();
x = t; breakCount = 1; label = null;
if (la.kind == 1) {
NoUSIdent(out id);
label = id.val;
- } else if (la.kind == 26 || la.kind == 90) {
- while (la.kind == 90) {
+ } else if (la.kind == 28 || la.kind == 96) {
+ while (la.kind == 96) {
Get();
breakCount++;
}
- } else SynErr(175);
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(176); Get();}
- Expect(26);
+ } else SynErr(181);
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(182); Get();}
+ Expect(28);
s = label != null ? new BreakStmt(x, t, label) : new BreakStmt(x, t, breakCount);
break;
}
- case 87: case 93: {
+ case 93: case 99: {
ReturnStmt(out s);
break;
}
- case 57: {
+ case 59: {
SkeletonStmt(out s);
break;
}
- default: SynErr(177); break;
+ default: SynErr(183); break;
}
}
@@ -2146,18 +2370,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression e = dummyExpr; Attributes attrs = null;
IToken dotdotdot = null;
- Expect(99);
+ Expect(104);
x = t;
while (IsAttribute()) {
Attribute(ref attrs);
}
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out e, false, true);
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
dotdotdot = t;
- } else SynErr(178);
- Expect(26);
+ } else SynErr(184);
+ Expect(28);
if (dotdotdot != null) {
s = new SkeletonStatement(new AssertStmt(x, t, new LiteralExpr(x, true), attrs), dotdotdot, null);
} else {
@@ -2171,18 +2395,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression e = dummyExpr; Attributes attrs = null;
IToken dotdotdot = null;
- Expect(29);
+ Expect(31);
x = t;
while (IsAttribute()) {
Attribute(ref attrs);
}
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out e, false, true);
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
dotdotdot = t;
- } else SynErr(179);
- Expect(26);
+ } else SynErr(185);
+ Expect(28);
if (dotdotdot != null) {
s = new SkeletonStatement(new AssumeStmt(x, t, new LiteralExpr(x, true), attrs), dotdotdot, null);
} else {
@@ -2196,16 +2420,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken x; Expression e;
var args = new List<Expression>();
- Expect(100);
+ Expect(105);
x = t;
Expression(out e, false, true);
args.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Expression(out e, false, true);
args.Add(e);
}
- Expect(26);
+ Expect(28);
s = new PrintStmt(x, t, args);
}
@@ -2220,44 +2444,44 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Lhs(out e);
x = e.tok;
- if (la.kind == 26 || la.kind == 44) {
- while (la.kind == 44) {
+ if (la.kind == 28 || la.kind == 46) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
- Expect(26);
+ Expect(28);
endTok = t; rhss.Add(new ExprRhs(e, attrs));
- } else if (la.kind == 21 || la.kind == 92 || la.kind == 94) {
+ } else if (la.kind == 22 || la.kind == 25 || la.kind == 98) {
lhss.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Lhs(out e);
lhss.Add(e);
}
- if (la.kind == 92) {
+ if (la.kind == 98) {
Get();
x = t;
Rhs(out r);
rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Rhs(out r);
rhss.Add(r);
}
- } else if (la.kind == 94) {
+ } else if (la.kind == 25) {
Get();
x = t;
if (la.kind == _assume) {
- Expect(29);
+ Expect(31);
suchThatAssume = t;
}
Expression(out suchThat, false, true);
- } else SynErr(180);
- Expect(26);
+ } else SynErr(186);
+ Expect(28);
endTok = t;
- } else if (la.kind == 20) {
+ } else if (la.kind == 21) {
Get();
SemErr(t, "invalid statement (did you forget the 'label' keyword?)");
- } else SynErr(181);
+ } else SynErr(187);
if (suchThat != null) {
s = new AssignSuchThatStmt(x, endTok, lhss, suchThat, suchThatAssume, null);
} else {
@@ -2280,76 +2504,117 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression suchThat = null;
Attributes attrs = null;
IToken endTok;
+ s = dummyStmt;
- if (la.kind == 70) {
+ if (la.kind == 62) {
Get();
isGhost = true; x = t;
}
- Expect(75);
+ Expect(81);
if (!isGhost) { x = t; }
- while (la.kind == 44) {
- Attribute(ref attrs);
- }
- LocalIdentTypeOptional(out d, isGhost);
- lhss.Add(d); d.Attributes = attrs; attrs = null;
- while (la.kind == 21) {
- Get();
- while (la.kind == 44) {
+ if (la.kind == 1 || la.kind == 46) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
LocalIdentTypeOptional(out d, isGhost);
lhss.Add(d); d.Attributes = attrs; attrs = null;
- }
- if (la.kind == 44 || la.kind == 92 || la.kind == 94) {
- if (la.kind == 92) {
+ while (la.kind == 22) {
Get();
- assignTok = t;
- Rhs(out r);
- rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 46) {
+ Attribute(ref attrs);
+ }
+ LocalIdentTypeOptional(out d, isGhost);
+ lhss.Add(d); d.Attributes = attrs; attrs = null;
+ }
+ if (la.kind == 25 || la.kind == 46 || la.kind == 98) {
+ if (la.kind == 98) {
Get();
+ assignTok = t;
Rhs(out r);
rhss.Add(r);
+ while (la.kind == 22) {
+ Get();
+ Rhs(out r);
+ rhss.Add(r);
+ }
+ } else {
+ while (la.kind == 46) {
+ Attribute(ref attrs);
+ }
+ Expect(25);
+ assignTok = t;
+ if (la.kind == _assume) {
+ Expect(31);
+ suchThatAssume = t;
+ }
+ Expression(out suchThat, false, true);
}
+ }
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(188); Get();}
+ Expect(28);
+ endTok = t;
+ ConcreteUpdateStatement update;
+ if (suchThat != null) {
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new AssignSuchThatStmt(assignTok, endTok, ies, suchThat, suchThatAssume, attrs);
+ } else if (rhss.Count == 0) {
+ update = null;
} else {
- while (la.kind == 44) {
- Attribute(ref attrs);
- }
- Expect(94);
- assignTok = t;
- if (la.kind == _assume) {
- Expect(29);
- suchThatAssume = t;
+ var ies = new List<Expression>();
+ foreach (var lhs in lhss) {
+ ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
+ }
+ update = new UpdateStmt(assignTok, endTok, ies, rhss);
+ }
+ s = new VarDeclStmt(x, endTok, lhss, update);
+
+ } else if (la.kind == 50) {
+ Get();
+ var letLHSs = new List<CasePattern>();
+ var letRHSs = new List<Expression>();
+ List<CasePattern> arguments = new List<CasePattern>();
+ CasePattern pat;
+ Expression e = dummyExpr;
+ IToken id = t;
+
+ if (la.kind == 1 || la.kind == 50) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
+ Get();
+ CasePattern(out pat);
+ arguments.Add(pat);
}
- Expression(out suchThat, false, true);
}
- }
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(182); Get();}
- Expect(26);
- endTok = t;
- ConcreteUpdateStatement update;
- if (suchThat != null) {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new IdentifierExpr(lhs.Tok, lhs.Name));
- }
- update = new AssignSuchThatStmt(assignTok, endTok, ies, suchThat, suchThatAssume, attrs);
- } else if (rhss.Count == 0) {
- update = null;
- } else {
- var ies = new List<Expression>();
- foreach (var lhs in lhss) {
- ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));
- }
- update = new UpdateStmt(assignTok, endTok, ies, rhss);
- }
- s = new VarDeclStmt(x, endTok, lhss, update);
-
+ Expect(51);
+ theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists
+ string ctor = BuiltIns.TupleTypeCtorName; //use the TupleTypeCtors
+ pat = new CasePattern(id, ctor, arguments);
+ if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }
+ letLHSs.Add(pat);
+
+ if (la.kind == 98) {
+ Get();
+ } else if (la.kind == 25 || la.kind == 46) {
+ while (la.kind == 46) {
+ Attribute(ref attrs);
+ }
+ Expect(25);
+ SemErr(pat.tok, "LHS of assign-such-that expression must be variables, not general patterns");
+ } else SynErr(189);
+ Expression(out e, false, true);
+ letRHSs.Add(e);
+ Expect(28);
+ s = new LetStmt(e.tok, e.tok, letLHSs, letRHSs);
+ } else SynErr(190);
}
void IfStmt(out Statement/*!*/ ifStmt) {
Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;
- Expression guard = null; IToken guardEllipsis = null;
+ Expression guard = null; IToken guardEllipsis = null; bool isExistentialGuard = false;
BlockStmt/*!*/ thn;
BlockStmt/*!*/ bs;
Statement/*!*/ s;
@@ -2358,13 +2623,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<GuardedAlternative> alternatives;
ifStmt = dummyStmt; // to please the compiler
- Expect(96);
+ Expect(101);
x = t;
if (IsAlternative()) {
- AlternativeBlock(out alternatives, out endTok);
+ AlternativeBlock(true, out alternatives, out endTok);
ifStmt = new AlternativeStmt(x, endTok, alternatives);
- } else if (StartOf(20)) {
- if (StartOf(21)) {
+ } else if (StartOf(22)) {
+ if (IsExistentialGuard()) {
+ ExistentialGuard(out guard, true);
+ isExistentialGuard = true;
+ } else if (StartOf(23)) {
Guard(out guard);
} else {
Get();
@@ -2372,23 +2640,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
BlockStmt(out thn, out bodyStart, out bodyEnd);
endTok = thn.EndTok;
- if (la.kind == 33) {
+ if (la.kind == 35) {
Get();
- if (la.kind == 96) {
+ if (la.kind == 101) {
IfStmt(out s);
els = s; endTok = s.EndTok;
- } else if (la.kind == 44) {
+ } else if (la.kind == 46) {
BlockStmt(out bs, out bodyStart, out bodyEnd);
els = bs; endTok = bs.EndTok;
- } else SynErr(183);
+ } else SynErr(191);
}
if (guardEllipsis != null) {
- ifStmt = new SkeletonStatement(new IfStmt(x, endTok, guard, thn, els), guardEllipsis, null);
+ ifStmt = new SkeletonStatement(new IfStmt(x, endTok, isExistentialGuard, guard, thn, els), guardEllipsis, null);
} else {
- ifStmt = new IfStmt(x, endTok, guard, thn, els);
+ ifStmt = new IfStmt(x, endTok, isExistentialGuard, guard, thn, els);
}
- } else SynErr(184);
+ } else SynErr(192);
}
void WhileStmt(out Statement stmt) {
@@ -2407,33 +2675,33 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
stmt = dummyStmt; // to please the compiler
bool isDirtyLoop = true;
- Expect(97);
+ Expect(102);
x = t;
if (IsLoopSpec() || IsAlternative()) {
- while (StartOf(22)) {
+ while (StartOf(24)) {
LoopSpec(invariants, decreases, ref mod, ref decAttrs, ref modAttrs);
}
- AlternativeBlock(out alternatives, out endTok);
+ AlternativeBlock(false, out alternatives, out endTok);
stmt = new AlternativeLoopStmt(x, endTok, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), alternatives);
- } else if (StartOf(20)) {
- if (StartOf(21)) {
+ } else if (StartOf(22)) {
+ if (StartOf(23)) {
Guard(out guard);
Contract.Assume(guard == null || cce.Owner.None(guard));
} else {
Get();
guardEllipsis = t;
}
- while (StartOf(22)) {
+ while (StartOf(24)) {
LoopSpec(invariants, decreases, ref mod, ref decAttrs, ref modAttrs);
}
if (la.kind == _lbrace) {
BlockStmt(out body, out bodyStart, out bodyEnd);
endTok = body.EndTok; isDirtyLoop = false;
} else if (la.kind == _ellipsis) {
- Expect(57);
+ Expect(59);
bodyEllipsis = t; endTok = t; isDirtyLoop = false;
- } else if (StartOf(23)) {
- } else SynErr(185);
+ } else if (StartOf(25)) {
+ } else SynErr(193);
if (guardEllipsis != null || bodyEllipsis != null) {
if (mod != null) {
SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
@@ -2451,7 +2719,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
stmt = new WhileStmt(x, endTok, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
}
- } else SynErr(186);
+ } else SynErr(194);
}
void MatchStmt(out Statement/*!*/ s) {
@@ -2460,23 +2728,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<MatchCaseStmt/*!*/> cases = new List<MatchCaseStmt/*!*/>();
bool usesOptionalBrace = false;
- Expect(98);
+ Expect(103);
x = t;
Expression(out e, true, true);
if (la.kind == _lbrace) {
- Expect(44);
+ Expect(46);
usesOptionalBrace = true;
- while (la.kind == 31) {
+ while (la.kind == 33) {
CaseStatement(out c);
cases.Add(c);
}
- Expect(45);
- } else if (StartOf(23)) {
+ Expect(47);
+ } else if (StartOf(25)) {
while (la.kind == _case) {
CaseStatement(out c);
cases.Add(c);
}
- } else SynErr(187);
+ } else SynErr(195);
s = new MatchStmt(x, t, e, cases, usesOptionalBrace);
}
@@ -2493,38 +2761,38 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken bodyStart, bodyEnd;
IToken tok = Token.NoToken;
- if (la.kind == 101) {
+ if (la.kind == 106) {
Get();
x = t; tok = x;
- } else if (la.kind == 102) {
+ } else if (la.kind == 107) {
Get();
x = t;
errors.Warning(t, "the 'parallel' keyword has been deprecated; the comprehension statement now uses the keyword 'forall' (and the parentheses around the bound variables are now optional)");
- } else SynErr(188);
+ } else SynErr(196);
if (la.kind == _openparen) {
- Expect(48);
+ Expect(50);
if (la.kind == 1) {
QuantifierDomain(out bvars, out attrs, out range);
}
- Expect(49);
- } else if (StartOf(24)) {
+ Expect(51);
+ } else if (StartOf(26)) {
if (la.kind == _ident) {
QuantifierDomain(out bvars, out attrs, out range);
}
- } else SynErr(189);
+ } else SynErr(197);
if (bvars == null) { bvars = new List<BoundVar>(); }
if (range == null) { range = new LiteralExpr(x, true); }
- while (la.kind == 85 || la.kind == 86) {
+ while (la.kind == 91 || la.kind == 92) {
isFree = false;
- if (la.kind == 85) {
+ if (la.kind == 91) {
Get();
isFree = true;
errors.Warning(t, "the 'free' keyword is soon to be deprecated");
}
- Expect(86);
+ Expect(92);
Expression(out e, false, true);
ens.Add(new MaybeFreeExpression(e, isFree));
OldSemi();
@@ -2547,6 +2815,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void CalcStmt(out Statement s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x;
+ Attributes attrs = null;
CalcStmt.CalcOp op, calcOp = Microsoft.Dafny.CalcStmt.DefaultOp, resOp = Microsoft.Dafny.CalcStmt.DefaultOp;
var lines = new List<Expression>();
var hints = new List<BlockStmt>();
@@ -2557,9 +2826,12 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken opTok;
IToken danglingOperator = null;
- Expect(30);
+ Expect(32);
x = t;
- if (StartOf(25)) {
+ while (IsAttribute()) {
+ Attribute(ref attrs);
+ }
+ if (StartOf(27)) {
CalcOp(out opTok, out calcOp);
maybeOp = calcOp.ResultOp(calcOp); // guard against non-transitive calcOp (like !=)
if (maybeOp == null) {
@@ -2568,12 +2840,12 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
resOp = calcOp;
}
- Expect(44);
- while (StartOf(7)) {
+ Expect(46);
+ while (StartOf(9)) {
Expression(out e, false, true);
lines.Add(e); stepOp = calcOp; danglingOperator = null;
- Expect(26);
- if (StartOf(25)) {
+ Expect(28);
+ if (StartOf(27)) {
CalcOp(out opTok, out op);
maybeOp = resOp.ResultOp(op);
if (maybeOp == null) {
@@ -2592,20 +2864,20 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BlockStmt subBlock; Statement subCalc;
while (la.kind == _lbrace || la.kind == _calc) {
- if (la.kind == 44) {
+ if (la.kind == 46) {
BlockStmt(out subBlock, out t0, out t1);
hintEnd = subBlock.EndTok; subhints.Add(subBlock);
- } else if (la.kind == 30) {
+ } else if (la.kind == 32) {
CalcStmt(out subCalc);
hintEnd = subCalc.EndTok; subhints.Add(subCalc);
- } else SynErr(190);
+ } else SynErr(198);
}
var h = new BlockStmt(hintStart, hintEnd, subhints); // if the hint is empty, hintStart is the first token of the next line, but it doesn't matter because the block statement is just used as a container
hints.Add(h);
if (h.Body.Count != 0) { danglingOperator = null; }
}
- Expect(45);
+ Expect(47);
if (danglingOperator != null) {
SemErr(danglingOperator, "a calculation cannot end with an operator");
}
@@ -2613,7 +2885,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
// Repeat the last line to create a dummy line for the dangling hint
lines.Add(lines[lines.Count - 1]);
}
- s = new CalcStmt(x, t, calcOp, lines, hints, stepOps, resOp);
+ s = new CalcStmt(x, t, calcOp, lines, hints, stepOps, resOp, attrs);
}
@@ -2624,30 +2896,30 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BlockStmt body = null; IToken bodyStart;
IToken ellipsisToken = null;
- Expect(103);
+ Expect(108);
tok = t;
while (IsAttribute()) {
Attribute(ref attrs);
}
- if (StartOf(18)) {
+ if (StartOf(20)) {
FrameExpression(out fe, false, true);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
FrameExpression(out fe, false, true);
mod.Add(fe);
}
- } else if (la.kind == 57) {
+ } else if (la.kind == 59) {
Get();
ellipsisToken = t;
- } else SynErr(191);
- if (la.kind == 44) {
+ } else SynErr(199);
+ if (la.kind == 46) {
BlockStmt(out body, out bodyStart, out endTok);
- } else if (la.kind == 26) {
- while (!(la.kind == 0 || la.kind == 26)) {SynErr(192); Get();}
+ } else if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 28)) {SynErr(200); Get();}
Get();
endTok = t;
- } else SynErr(193);
+ } else SynErr(201);
s = new ModifyStmt(tok, endTok, mod, attrs, body);
if (ellipsisToken != null) {
s = new SkeletonStatement(s, ellipsisToken, null);
@@ -2661,23 +2933,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
AssignmentRhs r;
bool isYield = false;
- if (la.kind == 93) {
+ if (la.kind == 99) {
Get();
returnTok = t;
- } else if (la.kind == 87) {
+ } else if (la.kind == 93) {
Get();
returnTok = t; isYield = true;
- } else SynErr(194);
- if (StartOf(26)) {
+ } else SynErr(202);
+ if (StartOf(28)) {
Rhs(out r);
rhss = new List<AssignmentRhs>(); rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Rhs(out r);
rhss.Add(r);
}
}
- Expect(26);
+ Expect(28);
if (isYield) {
s = new YieldStmt(returnTok, t, rhss);
} else {
@@ -2691,22 +2963,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Expression> exprs = null;
IToken tok, dotdotdot, whereTok;
Expression e;
- Expect(57);
+ Expect(59);
dotdotdot = t;
- if (la.kind == 91) {
+ if (la.kind == 97) {
Get();
names = new List<IToken>(); exprs = new List<Expression>(); whereTok = t;
Ident(out tok);
names.Add(tok);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Ident(out tok);
names.Add(tok);
}
- Expect(92);
+ Expect(98);
Expression(out e, false, true);
exprs.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Expression(out e, false, true);
exprs.Add(e);
@@ -2717,7 +2989,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- Expect(26);
+ Expect(28);
s = new SkeletonStatement(dotdotdot, t, names, exprs);
}
@@ -2730,25 +3002,25 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
r = dummyRhs; // to please compiler
Attributes attrs = null;
- if (la.kind == 95) {
+ if (la.kind == 100) {
Get();
newToken = t;
TypeAndToken(out x, out ty);
- if (la.kind == 46 || la.kind == 48) {
- if (la.kind == 46) {
+ if (la.kind == 48 || la.kind == 50) {
+ if (la.kind == 48) {
Get();
ee = new List<Expression>();
Expressions(ee);
- Expect(47);
+ Expect(49);
var tmp = theBuiltIns.ArrayType(ee.Count, new IntType(), true);
} else {
x = null; args = new List<Expression/*!*/>();
Get();
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(49);
+ Expect(51);
}
}
if (ee != null) {
@@ -2759,14 +3031,14 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
r = new TypeRhs(newToken, ty);
}
- } else if (la.kind == 55) {
+ } else if (la.kind == 57) {
Get();
r = new HavocRhs(t);
- } else if (StartOf(7)) {
+ } else if (StartOf(9)) {
Expression(out e, false, true);
r = new ExprRhs(e);
- } else SynErr(195);
- while (la.kind == 44) {
+ } else SynErr(203);
+ while (la.kind == 46) {
Attribute(ref attrs);
}
r.Attributes = attrs;
@@ -2777,94 +3049,170 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 1) {
NameSegment(out e);
- while (la.kind == 25 || la.kind == 46 || la.kind == 48) {
+ while (la.kind == 27 || la.kind == 48 || la.kind == 50) {
Suffix(ref e);
}
- } else if (StartOf(27)) {
+ } else if (StartOf(29)) {
ConstAtomExpression(out e, false, false);
Suffix(ref e);
- while (la.kind == 25 || la.kind == 46 || la.kind == 48) {
+ while (la.kind == 27 || la.kind == 48 || la.kind == 50) {
Suffix(ref e);
}
- } else SynErr(196);
+ } else SynErr(204);
}
void Expressions(List<Expression> args) {
Expression e;
Expression(out e, true, true);
args.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Expression(out e, true, true);
args.Add(e);
}
}
- void AlternativeBlock(out List<GuardedAlternative> alternatives, out IToken endTok) {
+ void CasePattern(out CasePattern pat) {
+ IToken id; List<CasePattern> arguments;
+ BoundVar bv;
+ pat = null;
+
+ if (IsIdentParen()) {
+ Ident(out id);
+ Expect(50);
+ arguments = new List<CasePattern>();
+ if (la.kind == 1 || la.kind == 50) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
+ Get();
+ CasePattern(out pat);
+ arguments.Add(pat);
+ }
+ }
+ Expect(51);
+ pat = new CasePattern(id, id.val, arguments);
+ } else if (la.kind == 50) {
+ Get();
+ id = t;
+ arguments = new List<CasePattern>();
+
+ if (la.kind == 1 || la.kind == 50) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
+ Get();
+ CasePattern(out pat);
+ arguments.Add(pat);
+ }
+ }
+ Expect(51);
+ theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists
+ string ctor = BuiltIns.TupleTypeCtorName; //use the TupleTypeCtors
+ pat = new CasePattern(id, ctor, arguments);
+
+ } else if (la.kind == 1) {
+ IdentTypeOptional(out bv);
+ pat = new CasePattern(bv.tok, bv);
+
+ } else SynErr(205);
+ if (pat == null) {
+ pat = new CasePattern(t, "_ParseError", new List<CasePattern>());
+ }
+
+ }
+
+ void AlternativeBlock(bool allowExistentialGuards, out List<GuardedAlternative> alternatives, out IToken endTok) {
alternatives = new List<GuardedAlternative>();
IToken x;
- Expression e;
+ Expression e; bool isExistentialGuard;
List<Statement> body;
- Expect(44);
- while (la.kind == 31) {
- Get();
- x = t;
- Expression(out e, true, false);
- Expect(27);
+ Expect(46);
+ while (la.kind == 33) {
+ Get();
+ x = t; isExistentialGuard = false; e = dummyExpr;
+ if (allowExistentialGuards && IsExistentialGuard()) {
+ ExistentialGuard(out e, false );
+ isExistentialGuard = true;
+ } else if (StartOf(9)) {
+ Expression(out e, true, false);
+ } else SynErr(206);
+ Expect(29);
body = new List<Statement>();
- while (StartOf(15)) {
+ while (StartOf(17)) {
Stmt(body);
}
- alternatives.Add(new GuardedAlternative(x, e, body));
+ alternatives.Add(new GuardedAlternative(x, isExistentialGuard, e, body));
}
- Expect(45);
+ Expect(47);
endTok = t;
}
+ void ExistentialGuard(out Expression e, bool allowLambda) {
+ var bvars = new List<BoundVar>();
+ BoundVar bv; IToken x;
+ Attributes attrs = null;
+ Expression body;
+
+ IdentTypeOptional(out bv);
+ bvars.Add(bv); x = bv.tok;
+ while (la.kind == 22) {
+ Get();
+ IdentTypeOptional(out bv);
+ bvars.Add(bv);
+ }
+ while (la.kind == 46) {
+ Attribute(ref attrs);
+ }
+ Expect(25);
+ Expression(out body, true, allowLambda);
+ e = new ExistsExpr(x, bvars, null, body, attrs);
+ }
+
void Guard(out Expression e) {
Expression/*!*/ ee; e = null;
- if (la.kind == 55) {
+ if (la.kind == 57) {
Get();
e = null;
} else if (IsParenStar()) {
- Expect(48);
- Expect(55);
- Expect(49);
+ Expect(50);
+ Expect(57);
+ Expect(51);
e = null;
- } else if (StartOf(7)) {
+ } else if (StartOf(9)) {
Expression(out ee, true, true);
e = ee;
- } else SynErr(197);
+ } else SynErr(207);
}
void LoopSpec(List<MaybeFreeExpression> invariants, List<Expression> decreases, ref List<FrameExpression> mod, ref Attributes decAttrs, ref Attributes modAttrs) {
Expression e; FrameExpression fe;
bool isFree = false; Attributes attrs = null;
- if (la.kind == 35 || la.kind == 85) {
- while (!(la.kind == 0 || la.kind == 35 || la.kind == 85)) {SynErr(198); Get();}
- if (la.kind == 85) {
+ if (la.kind == 37 || la.kind == 91) {
+ while (!(la.kind == 0 || la.kind == 37 || la.kind == 91)) {SynErr(208); Get();}
+ if (la.kind == 91) {
Get();
isFree = true; errors.Warning(t, "the 'free' keyword is soon to be deprecated");
}
- Expect(35);
+ Expect(37);
while (IsAttribute()) {
Attribute(ref attrs);
}
Expression(out e, false, true);
invariants.Add(new MaybeFreeExpression(e, isFree, attrs));
OldSemi();
- } else if (la.kind == 34) {
- while (!(la.kind == 0 || la.kind == 34)) {SynErr(199); Get();}
+ } else if (la.kind == 36) {
+ while (!(la.kind == 0 || la.kind == 36)) {SynErr(209); Get();}
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, true, true);
OldSemi();
- } else if (la.kind == 41) {
- while (!(la.kind == 0 || la.kind == 41)) {SynErr(200); Get();}
+ } else if (la.kind == 43) {
+ while (!(la.kind == 0 || la.kind == 43)) {SynErr(210); Get();}
Get();
mod = mod ?? new List<FrameExpression>();
while (IsAttribute()) {
@@ -2872,43 +3220,59 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
FrameExpression(out fe, false, true);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
FrameExpression(out fe, false, true);
mod.Add(fe);
}
OldSemi();
- } else SynErr(201);
+ } else SynErr(211);
}
void CaseStatement(out MatchCaseStmt/*!*/ c) {
Contract.Ensures(Contract.ValueAtReturn(out c) != null);
IToken/*!*/ x, id;
- List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
- BoundVar/*!*/ bv;
+ List<CasePattern/*!*/> arguments = new List<CasePattern/*!*/>();
+ CasePattern/*!*/ pat;
List<Statement/*!*/> body = new List<Statement/*!*/>();
+ string/*!*/ name = "";
- Expect(31);
+ Expect(33);
x = t;
- Ident(out id);
- if (la.kind == 48) {
+ if (la.kind == 1) {
+ Ident(out id);
+ name = id.val;
+ if (la.kind == 50) {
+ Get();
+ if (la.kind == 1 || la.kind == 50) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
+ Get();
+ CasePattern(out pat);
+ arguments.Add(pat);
+ }
+ }
+ Expect(51);
+ }
+ } else if (la.kind == 50) {
Get();
- IdentTypeOptional(out bv);
- arguments.Add(bv);
- while (la.kind == 21) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
Get();
- IdentTypeOptional(out bv);
- arguments.Add(bv);
+ CasePattern(out pat);
+ arguments.Add(pat);
}
- Expect(49);
- }
- Expect(27);
- while (!(StartOf(28))) {SynErr(202); Get();}
+ Expect(51);
+ } else SynErr(212);
+ Expect(29);
+ while (!(StartOf(30))) {SynErr(213); Get();}
while (IsNotEndOfCase()) {
Stmt(body);
- while (!(StartOf(28))) {SynErr(203); Get();}
+ while (!(StartOf(30))) {SynErr(214); Get();}
}
- c = new MatchCaseStmt(x, id.val, arguments, body);
+ c = new MatchCaseStmt(x, name, arguments, body);
}
void QuantifierDomain(out List<BoundVar> bvars, out Attributes attrs, out Expression range) {
@@ -2919,7 +3283,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out bv);
bvars.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
IdentTypeOptional(out bv);
bvars.Add(bv);
@@ -2928,7 +3292,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Attribute(ref attrs);
}
if (la.kind == _verticalbar) {
- Expect(22);
+ Expect(23);
Expression(out range, true, true);
}
}
@@ -2939,73 +3303,73 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = null;
switch (la.kind) {
- case 52: {
+ case 54: {
Get();
x = t; binOp = BinaryExpr.Opcode.Eq;
- if (la.kind == 104) {
+ if (la.kind == 109) {
Get();
- Expect(46);
+ Expect(48);
Expression(out k, true, true);
- Expect(47);
+ Expect(49);
}
break;
}
- case 50: {
+ case 52: {
Get();
x = t; binOp = BinaryExpr.Opcode.Lt;
break;
}
- case 51: {
+ case 53: {
Get();
x = t; binOp = BinaryExpr.Opcode.Gt;
break;
}
- case 105: {
+ case 110: {
Get();
x = t; binOp = BinaryExpr.Opcode.Le;
break;
}
- case 106: {
+ case 111: {
Get();
x = t; binOp = BinaryExpr.Opcode.Ge;
break;
}
- case 53: {
+ case 55: {
Get();
x = t; binOp = BinaryExpr.Opcode.Neq;
break;
}
- case 54: {
+ case 56: {
Get();
x = t; binOp = BinaryExpr.Opcode.Neq;
break;
}
- case 107: {
+ case 112: {
Get();
x = t; binOp = BinaryExpr.Opcode.Le;
break;
}
- case 108: {
+ case 113: {
Get();
x = t; binOp = BinaryExpr.Opcode.Ge;
break;
}
- case 109: case 110: {
+ case 114: case 115: {
EquivOp();
x = t; binOp = BinaryExpr.Opcode.Iff;
break;
}
- case 111: case 112: {
+ case 116: case 117: {
ImpliesOp();
x = t; binOp = BinaryExpr.Opcode.Imp;
break;
}
- case 113: case 114: {
+ case 118: case 119: {
ExpliesOp();
x = t; binOp = BinaryExpr.Opcode.Exp;
break;
}
- default: SynErr(204); break;
+ default: SynErr(215); break;
}
if (k == null) {
op = new Microsoft.Dafny.CalcStmt.BinaryCalcOp(binOp);
@@ -3016,75 +3380,75 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void EquivOp() {
- if (la.kind == 109) {
+ if (la.kind == 114) {
Get();
- } else if (la.kind == 110) {
+ } else if (la.kind == 115) {
Get();
- } else SynErr(205);
+ } else SynErr(216);
}
void ImpliesOp() {
- if (la.kind == 111) {
+ if (la.kind == 116) {
Get();
- } else if (la.kind == 112) {
+ } else if (la.kind == 117) {
Get();
- } else SynErr(206);
+ } else SynErr(217);
}
void ExpliesOp() {
- if (la.kind == 113) {
+ if (la.kind == 118) {
Get();
- } else if (la.kind == 114) {
+ } else if (la.kind == 119) {
Get();
- } else SynErr(207);
+ } else SynErr(218);
}
void AndOp() {
- if (la.kind == 115) {
+ if (la.kind == 120) {
Get();
- } else if (la.kind == 116) {
+ } else if (la.kind == 121) {
Get();
- } else SynErr(208);
+ } else SynErr(219);
}
void OrOp() {
- if (la.kind == 117) {
+ if (la.kind == 122) {
Get();
- } else if (la.kind == 118) {
+ } else if (la.kind == 123) {
Get();
- } else SynErr(209);
+ } else SynErr(220);
}
void NegOp() {
- if (la.kind == 119) {
+ if (la.kind == 124) {
Get();
- } else if (la.kind == 120) {
+ } else if (la.kind == 125) {
Get();
- } else SynErr(210);
+ } else SynErr(221);
}
void Forall() {
- if (la.kind == 101) {
+ if (la.kind == 106) {
Get();
- } else if (la.kind == 121) {
+ } else if (la.kind == 126) {
Get();
- } else SynErr(211);
+ } else SynErr(222);
}
void Exists() {
- if (la.kind == 122) {
+ if (la.kind == 127) {
Get();
- } else if (la.kind == 123) {
+ } else if (la.kind == 128) {
Get();
- } else SynErr(212);
+ } else SynErr(223);
}
void QSep() {
- if (la.kind == 23) {
+ if (la.kind == 24) {
Get();
- } else if (la.kind == 24) {
+ } else if (la.kind == 26) {
Get();
- } else SynErr(213);
+ } else SynErr(224);
}
void EquivExpression(out Expression e0, bool allowSemi, bool allowLambda) {
@@ -3102,23 +3466,24 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
LogicalExpression(out e0, allowSemi, allowLambda);
if (IsImpliesOp() || IsExpliesOp()) {
- if (la.kind == 111 || la.kind == 112) {
+ if (la.kind == 116 || la.kind == 117) {
ImpliesOp();
x = t;
ImpliesExpression(out e1, allowSemi, allowLambda);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.Imp, e0, e1);
- } else if (la.kind == 113 || la.kind == 114) {
+ } else if (la.kind == 118 || la.kind == 119) {
ExpliesOp();
x = t;
LogicalExpression(out e1, allowSemi, allowLambda);
- e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e0, e1);
+ e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0);
while (IsExpliesOp()) {
ExpliesOp();
x = t;
LogicalExpression(out e1, allowSemi, allowLambda);
- e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e0, e1);
+ e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0);
+
}
- } else SynErr(214);
+ } else SynErr(225);
}
}
@@ -3126,7 +3491,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
RelationalExpression(out e0, allowSemi, allowLambda);
if (IsAndOp() || IsOrOp()) {
- if (la.kind == 115 || la.kind == 116) {
+ if (la.kind == 120 || la.kind == 121) {
AndOp();
x = t;
RelationalExpression(out e1, allowSemi, allowLambda);
@@ -3137,7 +3502,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
RelationalExpression(out e1, allowSemi, allowLambda);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1);
}
- } else if (la.kind == 117 || la.kind == 118) {
+ } else if (la.kind == 122 || la.kind == 123) {
OrOp();
x = t;
RelationalExpression(out e1, allowSemi, allowLambda);
@@ -3148,7 +3513,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
RelationalExpression(out e1, allowSemi, allowLambda);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1);
}
- } else SynErr(215);
+ } else SynErr(226);
}
}
@@ -3281,63 +3646,63 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
k = null;
switch (la.kind) {
- case 52: {
+ case 54: {
Get();
x = t; op = BinaryExpr.Opcode.Eq;
- if (la.kind == 104) {
+ if (la.kind == 109) {
Get();
- Expect(46);
+ Expect(48);
Expression(out k, true, true);
- Expect(47);
+ Expect(49);
}
break;
}
- case 50: {
+ case 52: {
Get();
x = t; op = BinaryExpr.Opcode.Lt;
break;
}
- case 51: {
+ case 53: {
Get();
x = t; op = BinaryExpr.Opcode.Gt;
break;
}
- case 105: {
+ case 110: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 106: {
+ case 111: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- case 53: {
+ case 55: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
- if (la.kind == 104) {
+ if (la.kind == 109) {
Get();
- Expect(46);
+ Expect(48);
Expression(out k, true, true);
- Expect(47);
+ Expect(49);
}
break;
}
- case 124: {
+ case 129: {
Get();
x = t; op = BinaryExpr.Opcode.In;
break;
}
- case 56: {
+ case 58: {
Get();
x = t; op = BinaryExpr.Opcode.NotIn;
break;
}
- case 119: {
+ case 124: {
Get();
x = t; y = Token.NoToken;
if (la.val == "!") {
- Expect(119);
+ Expect(124);
y = t;
}
if (y == Token.NoToken) {
@@ -3351,22 +3716,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
break;
}
- case 54: {
+ case 56: {
Get();
x = t; op = BinaryExpr.Opcode.Neq;
break;
}
- case 107: {
+ case 112: {
Get();
x = t; op = BinaryExpr.Opcode.Le;
break;
}
- case 108: {
+ case 113: {
Get();
x = t; op = BinaryExpr.Opcode.Ge;
break;
}
- default: SynErr(216); break;
+ default: SynErr(227); break;
}
}
@@ -3382,80 +3747,87 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void AddOp(out IToken x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 125) {
+ if (la.kind == 76) {
Get();
x = t; op = BinaryExpr.Opcode.Add;
- } else if (la.kind == 126) {
+ } else if (la.kind == 130) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(217);
+ } else SynErr(228);
}
void UnaryExpression(out Expression e, bool allowSemi, bool allowLambda) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr;
- if (la.kind == 126) {
+ if (la.kind == 130) {
Get();
x = t;
UnaryExpression(out e, allowSemi, allowLambda);
e = new NegationExpression(x, e);
- } else if (la.kind == 119 || la.kind == 120) {
+ } else if (la.kind == 124 || la.kind == 125) {
NegOp();
x = t;
UnaryExpression(out e, allowSemi, allowLambda);
e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Not, e);
} else if (IsMapDisplay()) {
- Expect(16);
+ Expect(17);
x = t;
MapDisplayExpr(x, true, out e);
while (IsSuffix()) {
Suffix(ref e);
}
} else if (IsIMapDisplay()) {
- Expect(17);
+ Expect(18);
x = t;
MapDisplayExpr(x, false, out e);
while (IsSuffix()) {
Suffix(ref e);
}
+ } else if (IsISetDisplay()) {
+ Expect(14);
+ x = t;
+ ISetDisplayExpr(x, false, out e);
+ while (IsSuffix()) {
+ Suffix(ref e);
+ }
} else if (IsLambda(allowLambda)) {
LambdaExpression(out e, allowSemi);
- } else if (StartOf(29)) {
+ } else if (StartOf(31)) {
EndlessExpression(out e, allowSemi, allowLambda);
} else if (la.kind == 1) {
NameSegment(out e);
while (IsSuffix()) {
Suffix(ref e);
}
- } else if (la.kind == 44 || la.kind == 46) {
+ } else if (la.kind == 46 || la.kind == 48) {
DisplayExpr(out e);
while (IsSuffix()) {
Suffix(ref e);
}
- } else if (la.kind == 14) {
+ } else if (la.kind == 15) {
MultiSetExpr(out e);
while (IsSuffix()) {
Suffix(ref e);
}
- } else if (StartOf(27)) {
+ } else if (StartOf(29)) {
ConstAtomExpression(out e, allowSemi, allowLambda);
while (IsSuffix()) {
Suffix(ref e);
}
- } else SynErr(218);
+ } else SynErr(229);
}
void MulOp(out IToken x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 55) {
+ if (la.kind == 57) {
Get();
x = t; op = BinaryExpr.Opcode.Mul;
- } else if (la.kind == 127) {
+ } else if (la.kind == 131) {
Get();
x = t; op = BinaryExpr.Opcode.Div;
- } else if (la.kind == 128) {
+ } else if (la.kind == 132) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(219);
+ } else SynErr(230);
}
void MapDisplayExpr(IToken/*!*/ mapToken, bool finite, out Expression e) {
@@ -3463,12 +3835,12 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<ExpressionPair/*!*/>/*!*/ elements= new List<ExpressionPair/*!*/>() ;
e = dummyExpr;
- Expect(46);
- if (StartOf(7)) {
+ Expect(48);
+ if (StartOf(9)) {
MapLiteralExpressions(out elements);
}
e = new MapDisplayExpr(mapToken, finite, elements);
- Expect(47);
+ Expect(49);
}
void Suffix(ref Expression e) {
@@ -3477,66 +3849,83 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression e0 = null; Expression e1 = null; Expression ee; bool anyDots = false;
List<Expression> multipleLengths = null; bool takeRest = false; // takeRest is relevant only if multipleLengths is non-null
List<Expression> multipleIndices = null;
+ List<Tuple<IToken, string, Expression>> updates;
+ Expression v;
- if (la.kind == 25) {
- DotSuffix(out id, out x);
- if (x != null) {
- // process id as a Suffix in its own right
- e = new ExprDotName(id, e, id.val, null);
- id = x; // move to the next Suffix
- }
- IToken openParen = null; List<Type> typeArgs = null; List<Expression> args = null;
-
- if (IsGenericInstantiation()) {
- typeArgs = new List<Type>();
- GenericInstantiation(typeArgs);
- } else if (la.kind == 104) {
- HashCall(id, out openParen, out typeArgs, out args);
- } else if (StartOf(30)) {
- } else SynErr(220);
- e = new ExprDotName(id, e, id.val, typeArgs);
- if (openParen != null) {
- e = new ApplySuffix(openParen, e, args);
- }
-
- } else if (la.kind == 46) {
+ if (la.kind == 27) {
+ Get();
+ if (la.kind == 50) {
+ Get();
+ x = t; updates = new List<Tuple<IToken, string, Expression>>();
+ MemberBindingUpdate(out id, out v);
+ updates.Add(Tuple.Create(id, id.val, v));
+ while (la.kind == 22) {
+ Get();
+ MemberBindingUpdate(out id, out v);
+ updates.Add(Tuple.Create(id, id.val, v));
+ }
+ Expect(51);
+ e = new DatatypeUpdateExpr(x, e, updates);
+ } else if (StartOf(32)) {
+ DotSuffix(out id, out x);
+ if (x != null) {
+ // process id as a Suffix in its own right
+ e = new ExprDotName(id, e, id.val, null);
+ id = x; // move to the next Suffix
+ }
+ IToken openParen = null; List<Type> typeArgs = null; List<Expression> args = null;
+
+ if (IsGenericInstantiation()) {
+ typeArgs = new List<Type>();
+ GenericInstantiation(typeArgs);
+ } else if (la.kind == 109) {
+ HashCall(id, out openParen, out typeArgs, out args);
+ } else if (StartOf(33)) {
+ } else SynErr(231);
+ e = new ExprDotName(id, e, id.val, typeArgs);
+ if (openParen != null) {
+ e = new ApplySuffix(openParen, e, args);
+ }
+
+ } else SynErr(232);
+ } else if (la.kind == 48) {
Get();
x = t;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out ee, true, true);
e0 = ee;
- if (la.kind == 135) {
+ if (la.kind == 139) {
Get();
anyDots = true;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out ee, true, true);
e1 = ee;
}
- } else if (la.kind == 92) {
+ } else if (la.kind == 98) {
Get();
Expression(out ee, true, true);
e1 = ee;
- } else if (la.kind == 20) {
+ } else if (la.kind == 21) {
Get();
multipleLengths = new List<Expression>();
multipleLengths.Add(e0); // account for the Expression read before the colon
takeRest = true;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out ee, true, true);
multipleLengths.Add(ee); takeRest = false;
while (IsNonFinalColon()) {
- Expect(20);
+ Expect(21);
Expression(out ee, true, true);
multipleLengths.Add(ee);
}
- if (la.kind == 20) {
+ if (la.kind == 21) {
Get();
takeRest = true;
}
}
- } else if (la.kind == 21 || la.kind == 47) {
- while (la.kind == 21) {
+ } else if (la.kind == 22 || la.kind == 49) {
+ while (la.kind == 22) {
Get();
Expression(out ee, true, true);
if (multipleIndices == null) {
@@ -3546,15 +3935,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
multipleIndices.Add(ee);
}
- } else SynErr(221);
- } else if (la.kind == 135) {
+ } else SynErr(233);
+ } else if (la.kind == 139) {
Get();
anyDots = true;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expression(out ee, true, true);
e1 = ee;
}
- } else SynErr(222);
+ } else SynErr(234);
if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
// make sure an array class with this dimensionality exists
@@ -3589,16 +3978,29 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- Expect(47);
- } else if (la.kind == 48) {
+ Expect(49);
+ } else if (la.kind == 50) {
Get();
IToken openParen = t; var args = new List<Expression>();
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(49);
+ Expect(51);
e = new ApplySuffix(openParen, e, args);
- } else SynErr(223);
+ } else SynErr(235);
+ }
+
+ void ISetDisplayExpr(IToken/*!*/ setToken, bool finite, out Expression e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ List<Expression> elements = new List<Expression/*!*/>();;
+ e = dummyExpr;
+
+ Expect(46);
+ if (StartOf(9)) {
+ Expressions(elements);
+ }
+ e = new SetDisplayExpr(setToken, finite, elements);
+ Expect(47);
}
void LambdaExpression(out Expression e, bool allowSemi) {
@@ -3614,22 +4016,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (la.kind == 1) {
WildIdent(out id, true);
x = t; bvs.Add(new BoundVar(id, id.val, new InferredTypeProxy()));
- } else if (la.kind == 48) {
+ } else if (la.kind == 50) {
Get();
x = t;
if (la.kind == 1) {
IdentTypeOptional(out bv);
bvs.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
IdentTypeOptional(out bv);
bvs.Add(bv);
}
}
- Expect(49);
- } else SynErr(224);
- while (la.kind == 42 || la.kind == 43) {
- if (la.kind == 42) {
+ Expect(51);
+ } else SynErr(236);
+ while (la.kind == 44 || la.kind == 45) {
+ if (la.kind == 44) {
Get();
PossiblyWildFrameExpression(out fe, true);
reads.Add(fe);
@@ -3653,56 +4055,64 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
switch (la.kind) {
- case 96: {
+ case 101: {
Get();
x = t;
Expression(out e, true, true);
- Expect(32);
+ Expect(34);
Expression(out e0, true, true);
- Expect(33);
+ Expect(35);
Expression(out e1, allowSemi, allowLambda);
e = new ITEExpr(x, e, e0, e1);
break;
}
- case 98: {
+ case 103: {
MatchExpression(out e, allowSemi, allowLambda);
break;
}
- case 101: case 121: case 122: case 123: {
+ case 106: case 126: case 127: case 128: {
QuantifierGuts(out e, allowSemi, allowLambda);
break;
}
case 13: {
- SetComprehensionExpr(out e, allowSemi, allowLambda);
+ Get();
+ x = t;
+ SetComprehensionExpr(x, true, out e, allowSemi, allowLambda);
+ break;
+ }
+ case 14: {
+ Get();
+ x = t;
+ SetComprehensionExpr(x, false, out e, allowSemi, allowLambda);
break;
}
- case 29: case 30: case 99: {
+ case 31: case 32: case 104: {
StmtInExpr(out s);
Expression(out e, allowSemi, allowLambda);
e = new StmtExpr(s.Tok, s, e);
break;
}
- case 70: case 75: {
+ case 62: case 81: {
LetExpr(out e, allowSemi, allowLambda);
break;
}
- case 16: {
+ case 17: {
Get();
x = t;
MapComprehensionExpr(x, true, out e, allowSemi, allowLambda);
break;
}
- case 17: {
+ case 18: {
Get();
x = t;
MapComprehensionExpr(x, false, out e, allowSemi, allowLambda);
break;
}
- case 89: {
+ case 95: {
NamedExpr(out e, allowSemi, allowLambda);
break;
}
- default: SynErr(225); break;
+ default: SynErr(237); break;
}
}
@@ -3714,10 +4124,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (IsGenericInstantiation()) {
typeArgs = new List<Type>();
GenericInstantiation(typeArgs);
- } else if (la.kind == 104) {
+ } else if (la.kind == 109) {
HashCall(id, out openParen, out typeArgs, out args);
- } else if (StartOf(30)) {
- } else SynErr(226);
+ } else if (StartOf(33)) {
+ } else SynErr(238);
e = new NameSegment(id, id.val, typeArgs);
if (openParen != null) {
e = new ApplySuffix(openParen, e, args);
@@ -3730,23 +4140,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken x; List<Expression> elements;
e = dummyExpr;
- if (la.kind == 44) {
+ if (la.kind == 46) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(elements);
}
- e = new SetDisplayExpr(x, elements);
- Expect(45);
- } else if (la.kind == 46) {
+ e = new SetDisplayExpr(x, true, elements);
+ Expect(47);
+ } else if (la.kind == 48) {
Get();
x = t; elements = new List<Expression/*!*/>();
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(elements);
}
e = new SeqDisplayExpr(x, elements);
- Expect(47);
- } else SynErr(227);
+ Expect(49);
+ } else SynErr(239);
}
void MultiSetExpr(out Expression e) {
@@ -3754,23 +4164,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
e = dummyExpr;
- Expect(14);
+ Expect(15);
x = t;
- if (la.kind == 44) {
+ if (la.kind == 46) {
Get();
elements = new List<Expression/*!*/>();
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(elements);
}
e = new MultiSetDisplayExpr(x, elements);
- Expect(45);
- } else if (la.kind == 48) {
+ Expect(47);
+ } else if (la.kind == 50) {
Get();
x = t; elements = new List<Expression/*!*/>();
Expression(out e, true, true);
e = new MultiSetFormingExpr(x, e);
- Expect(49);
- } else SynErr(228);
+ Expect(51);
+ } else SynErr(240);
}
void ConstAtomExpression(out Expression e, bool allowSemi, bool allowLambda) {
@@ -3779,17 +4189,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr; Type toType = null;
switch (la.kind) {
- case 129: {
+ case 133: {
Get();
e = new LiteralExpr(t, false);
break;
}
- case 130: {
+ case 134: {
Get();
e = new LiteralExpr(t, true);
break;
}
- case 131: {
+ case 135: {
Get();
e = new LiteralExpr(t);
break;
@@ -3804,12 +4214,12 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new LiteralExpr(t, d);
break;
}
- case 18: {
+ case 19: {
Get();
e = new CharLiteralExpr(t, t.val.Substring(1, t.val.Length - 2));
break;
}
- case 19: {
+ case 20: {
Get();
bool isVerbatimString;
string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);
@@ -3817,35 +4227,35 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
break;
}
- case 132: {
+ case 136: {
Get();
e = new ThisExpr(t);
break;
}
- case 133: {
+ case 137: {
Get();
x = t;
- Expect(48);
+ Expect(50);
Expression(out e, true, true);
- Expect(49);
+ Expect(51);
e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Fresh, e);
break;
}
- case 134: {
+ case 138: {
Get();
x = t;
- Expect(48);
+ Expect(50);
Expression(out e, true, true);
- Expect(49);
+ Expect(51);
e = new OldExpr(x, e);
break;
}
- case 22: {
+ case 23: {
Get();
x = t;
Expression(out e, true, true);
e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Cardinality, e);
- Expect(22);
+ Expect(23);
break;
}
case 8: case 10: {
@@ -3856,17 +4266,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
x = t; toType = new RealType();
}
- Expect(48);
+ Expect(50);
Expression(out e, true, true);
- Expect(49);
+ Expect(51);
e = new ConversionExpr(x, e, toType);
break;
}
- case 48: {
+ case 50: {
ParensExpression(out e, allowSemi, allowLambda);
break;
}
- default: SynErr(229); break;
+ default: SynErr(241); break;
}
}
@@ -3878,7 +4288,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
S = Util.RemoveUnderscores(t.val);
try {
- n = BigInteger.Parse(S);
+ n = BigIntegerParser.Parse(S);
} catch (System.FormatException) {
SemErr("incorrectly formatted number");
n = BigInteger.Zero;
@@ -3889,13 +4299,13 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
S = Util.RemoveUnderscores(t.val.Substring(2));
try {
// note: leading 0 required when parsing positive hex numbers
- n = BigInteger.Parse("0" + S, System.Globalization.NumberStyles.HexNumber);
+ n = BigIntegerParser.Parse("0" + S, System.Globalization.NumberStyles.HexNumber);
} catch (System.FormatException) {
SemErr("incorrectly formatted number");
n = BigInteger.Zero;
}
- } else SynErr(230);
+ } else SynErr(242);
}
void Dec(out Basetypes.BigDec d) {
@@ -3915,12 +4325,12 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken x;
var args = new List<Expression>();
- Expect(48);
+ Expect(50);
x = t;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(49);
+ Expect(51);
if (args.Count == 1) {
e = new ParensExpression(x, args[0]);
} else {
@@ -3933,26 +4343,26 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void LambdaArrow(out bool oneShot) {
oneShot = true;
- if (la.kind == 27) {
+ if (la.kind == 29) {
Get();
oneShot = false;
- } else if (la.kind == 28) {
+ } else if (la.kind == 30) {
Get();
oneShot = true;
- } else SynErr(231);
+ } else SynErr(243);
}
void MapLiteralExpressions(out List<ExpressionPair> elements) {
Expression/*!*/ d, r;
elements = new List<ExpressionPair/*!*/>();
Expression(out d, true, true);
- Expect(92);
+ Expect(98);
Expression(out r, true, true);
elements.Add(new ExpressionPair(d,r));
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Expression(out d, true, true);
- Expect(92);
+ Expect(98);
Expression(out r, true, true);
elements.Add(new ExpressionPair(d,r));
}
@@ -3968,10 +4378,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out bv);
bvars.Add(bv);
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
- if (la.kind == 22) {
+ if (la.kind == 23) {
Get();
Expression(out range, true, true);
}
@@ -3986,23 +4396,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<MatchCaseExpr/*!*/> cases = new List<MatchCaseExpr/*!*/>();
bool usesOptionalBrace = false;
- Expect(98);
+ Expect(103);
x = t;
Expression(out e, allowSemi, allowLambda);
if (la.kind == _lbrace) {
- Expect(44);
+ Expect(46);
usesOptionalBrace = true;
- while (la.kind == 31) {
+ while (la.kind == 33) {
CaseExpression(out c, true, true);
cases.Add(c);
}
- Expect(45);
- } else if (StartOf(31)) {
+ Expect(47);
+ } else if (StartOf(34)) {
while (la.kind == _case) {
CaseExpression(out c, allowSemi, allowLambda);
cases.Add(c);
}
- } else SynErr(232);
+ } else SynErr(244);
e = new MatchExpr(x, e, cases, usesOptionalBrace);
}
@@ -4014,13 +4424,13 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression range;
Expression/*!*/ body;
- if (la.kind == 101 || la.kind == 121) {
+ if (la.kind == 106 || la.kind == 126) {
Forall();
x = t; univ = true;
- } else if (la.kind == 122 || la.kind == 123) {
+ } else if (la.kind == 127 || la.kind == 128) {
Exists();
x = t;
- } else SynErr(233);
+ } else SynErr(245);
QuantifierDomain(out bvars, out attrs, out range);
QSep();
Expression(out body, allowSemi, allowLambda);
@@ -4032,47 +4442,44 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
- void SetComprehensionExpr(out Expression q, bool allowSemi, bool allowLambda) {
+ void SetComprehensionExpr(IToken setToken, bool finite, out Expression q, bool allowSemi, bool allowLambda) {
Contract.Ensures(Contract.ValueAtReturn(out q) != null);
- IToken x = Token.NoToken;
BoundVar bv;
List<BoundVar/*!*/> bvars = new List<BoundVar>();
Expression range;
Expression body = null;
Attributes attrs = null;
- Expect(13);
- x = t;
IdentTypeOptional(out bv);
bvars.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
IdentTypeOptional(out bv);
bvars.Add(bv);
}
- while (la.kind == 44) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
- Expect(22);
+ Expect(23);
Expression(out range, allowSemi, allowLambda);
if (IsQSep()) {
QSep();
Expression(out body, allowSemi, allowLambda);
}
if (body == null && bvars.Count != 1) { SemErr(t, "a set comprehension with more than one bound variable must have a term expression"); }
- q = new SetComprehension(x, bvars, range, body, attrs);
+ q = new SetComprehension(setToken, finite, bvars, range, body, attrs);
}
void StmtInExpr(out Statement s) {
s = dummyStmt;
- if (la.kind == 99) {
+ if (la.kind == 104) {
AssertStmt(out s);
- } else if (la.kind == 29) {
+ } else if (la.kind == 31) {
AssumeStmt(out s);
- } else if (la.kind == 30) {
+ } else if (la.kind == 32) {
CalcStmt(out s);
- } else SynErr(234);
+ } else SynErr(246);
}
void LetExpr(out Expression e, bool allowSemi, bool allowLambda) {
@@ -4085,30 +4492,30 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Attributes attrs = null;
e = dummyExpr;
- if (la.kind == 70) {
+ if (la.kind == 62) {
Get();
isGhost = true; x = t;
}
- Expect(75);
+ Expect(81);
if (!isGhost) { x = t; }
CasePattern(out pat);
if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }
letLHSs.Add(pat);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
CasePattern(out pat);
if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }
letLHSs.Add(pat);
}
- if (la.kind == 92) {
+ if (la.kind == 98) {
Get();
- } else if (la.kind == 44 || la.kind == 94) {
- while (la.kind == 44) {
+ } else if (la.kind == 25 || la.kind == 46) {
+ while (la.kind == 46) {
Attribute(ref attrs);
}
- Expect(94);
+ Expect(25);
exact = false;
foreach (var lhs in letLHSs) {
if (lhs.Arguments != null) {
@@ -4116,15 +4523,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- } else SynErr(235);
+ } else SynErr(247);
Expression(out e, false, true);
letRHSs.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 22) {
Get();
Expression(out e, false, true);
letRHSs.Add(e);
}
- Expect(26);
+ Expect(28);
Expression(out e, allowSemi, allowLambda);
e = new LetExpr(x, letLHSs, letRHSs, e, exact, attrs);
}
@@ -4134,89 +4541,87 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
Expression expr;
- Expect(89);
+ Expect(95);
x = t;
NoUSIdent(out d);
- Expect(20);
+ Expect(21);
Expression(out e, allowSemi, allowLambda);
expr = e;
e = new NamedExpr(x, d.val, expr);
}
- void CasePattern(out CasePattern pat) {
- IToken id; List<CasePattern> arguments;
- BoundVar bv;
- pat = null;
+ void CaseExpression(out MatchCaseExpr c, bool allowSemi, bool allowLambda) {
+ Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ x, id;
+ List<CasePattern/*!*/> arguments = new List<CasePattern/*!*/>();
+ CasePattern/*!*/ pat;
+ Expression/*!*/ body;
+ string/*!*/ name = "";
- if (IsIdentParen()) {
+ Expect(33);
+ x = t;
+ if (la.kind == 1) {
Ident(out id);
- Expect(48);
- arguments = new List<CasePattern>();
- if (la.kind == 1) {
- CasePattern(out pat);
- arguments.Add(pat);
- while (la.kind == 21) {
- Get();
+ name = id.val;
+ if (la.kind == 50) {
+ Get();
+ if (la.kind == 1 || la.kind == 50) {
CasePattern(out pat);
arguments.Add(pat);
+ while (la.kind == 22) {
+ Get();
+ CasePattern(out pat);
+ arguments.Add(pat);
+ }
}
+ Expect(51);
}
- Expect(49);
- pat = new CasePattern(id, id.val, arguments);
- } else if (la.kind == 1) {
- IdentTypeOptional(out bv);
- pat = new CasePattern(bv.tok, bv);
-
- } else SynErr(236);
- if (pat == null) {
- pat = new CasePattern(t, "_ParseError", new List<CasePattern>());
- }
-
- }
-
- void CaseExpression(out MatchCaseExpr c, bool allowSemi, bool allowLambda) {
- Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ x, id;
- List<BoundVar/*!*/> arguments = new List<BoundVar/*!*/>();
- BoundVar/*!*/ bv;
- Expression/*!*/ body;
-
- Expect(31);
- x = t;
- Ident(out id);
- if (la.kind == 48) {
+ } else if (la.kind == 50) {
Get();
- IdentTypeOptional(out bv);
- arguments.Add(bv);
- while (la.kind == 21) {
+ CasePattern(out pat);
+ arguments.Add(pat);
+ while (la.kind == 22) {
Get();
- IdentTypeOptional(out bv);
- arguments.Add(bv);
+ CasePattern(out pat);
+ arguments.Add(pat);
}
- Expect(49);
- }
- Expect(27);
+ Expect(51);
+ } else SynErr(248);
+ Expect(29);
Expression(out body, allowSemi, allowLambda);
- c = new MatchCaseExpr(x, id.val, arguments, body);
+ c = new MatchCaseExpr(x, name, arguments, body);
}
void HashCall(IToken id, out IToken openParen, out List<Type> typeArgs, out List<Expression> args) {
Expression k; args = new List<Expression>(); typeArgs = null;
- Expect(104);
+ Expect(109);
id.val = id.val + "#";
- if (la.kind == 50) {
+ if (la.kind == 52) {
typeArgs = new List<Type>();
GenericInstantiation(typeArgs);
}
- Expect(46);
+ Expect(48);
Expression(out k, true, true);
- Expect(47);
+ Expect(49);
args.Add(k);
- Expect(48);
+ Expect(50);
openParen = t;
- if (StartOf(7)) {
+ if (StartOf(9)) {
Expressions(args);
}
- Expect(49);
+ Expect(51);
+ }
+
+ void MemberBindingUpdate(out IToken id, out Expression e) {
+ id = Token.NoToken; e = dummyExpr;
+ if (la.kind == 1) {
+ Get();
+ id = t;
+ } else if (la.kind == 2) {
+ Get();
+ id = t;
+ } else SynErr(249);
+ Expect(98);
+ Expression(out e, true, true);
}
void DotSuffix(out IToken x, out IToken y) {
@@ -4224,7 +4629,6 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = Token.NoToken;
y = null;
- Expect(25);
if (la.kind == 1) {
Get();
x = t;
@@ -4252,13 +4656,13 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- } else if (la.kind == 43) {
+ } else if (la.kind == 45) {
Get();
x = t;
- } else if (la.kind == 42) {
+ } else if (la.kind == 44) {
Get();
x = t;
- } else SynErr(237);
+ } else SynErr(250);
}
@@ -4270,61 +4674,66 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Dafny();
Expect(0);
- Expect(0);
}
- static readonly bool[,]/*!*/ set = {
- {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_T,_x, _x,_T,_T,_T, _x,_x,_T,_T, _x,_x,_T,_T, _x,_T,_T,_T, _T,_T,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_x, _x,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_T,_x, _x,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_x,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_x,_x, _x,_T,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_T,_x, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_T,_x, _x,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_T,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_T, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_x,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_x, _x,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
- {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
- {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _T,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x},
- {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _T,_T,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x}
+ static readonly bool[,] set = {
+ {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _T,_x,_x,_T, _T,_T,_x,_x, _T,_T,_x,_x, _T,_T,_x,_T, _T,_T,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_x,_x, _T,_x,_x,_T, _T,_T,_T,_T, _T,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x,_x, _x,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_x,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x,_T, _x,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_T, _x,_T,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_T,_T, _T,_T,_T,_x, _T,_T,_T,_T, _x,_x,_T,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x,_x, _x,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_T, _T,_T,_T,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_T, _x,_T,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_T, _x,_T,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_T,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_T, _x,_T,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_T,_T,_T, _x,_T,_T,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _T,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_T,_T, _T,_x,_T,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_x,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_T, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_x,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_x, _x,_x},
+ {_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_T,_x, _x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_x,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_x,_T,_T,_x, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x},
+ {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x,_x, _x,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x},
+ {_T,_T,_T,_T, _T,_x,_x,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_T, _T,_T,_T,_T, _T,_x,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x,_x, _x,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_x,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_x}
};
} // end Parser
public class Errors {
- public int count = 0; // number of errors detected
- public System.IO.TextWriter/*!*/ errorStream = Console.Out; // error messages go to this stream
- public string errMsgFormat = "{0}({1},{2}): error: {3}"; // 0=filename, 1=line, 2=column, 3=text
- public string warningMsgFormat = "{0}({1},{2}): warning: {3}"; // 0=filename, 1=line, 2=column, 3=text
+ readonly ErrorReporter Reporting;
+ public int ErrorCount;
+
+ public Errors(ErrorReporter Reporting) {
+ Contract.Requires(Reporting != null);
+ this.Reporting = Reporting;
+ }
public void SynErr(string filename, int line, int col, int n) {
SynErr(filename, line, col, GetSyntaxErrorString(n));
}
- public virtual void SynErr(string filename, int line, int col, string/*!*/ msg) {
+ public void SynErr(string filename, int line, int col, string msg) {
Contract.Requires(msg != null);
- errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
- count++;
+ ErrorCount++;
+ Reporting.Error(MessageSource.Parser, filename, line, col, msg);
}
string GetSyntaxErrorString(int n) {
@@ -4344,257 +4753,266 @@ public class Errors {
case 11: s = "object expected"; break;
case 12: s = "string expected"; break;
case 13: s = "set expected"; break;
- case 14: s = "multiset expected"; break;
- case 15: s = "seq expected"; break;
- case 16: s = "map expected"; break;
- case 17: s = "imap expected"; break;
- case 18: s = "charToken expected"; break;
- case 19: s = "stringToken expected"; break;
- case 20: s = "colon expected"; break;
- case 21: s = "comma expected"; break;
- case 22: s = "verticalbar expected"; break;
- case 23: s = "doublecolon expected"; break;
- case 24: s = "bullet expected"; break;
- case 25: s = "dot expected"; break;
- case 26: s = "semi expected"; break;
- case 27: s = "darrow expected"; break;
- case 28: s = "arrow expected"; break;
- case 29: s = "assume expected"; break;
- case 30: s = "calc expected"; break;
- case 31: s = "case expected"; break;
- case 32: s = "then expected"; break;
- case 33: s = "else expected"; break;
- case 34: s = "decreases expected"; break;
- case 35: s = "invariant expected"; break;
- case 36: s = "function expected"; break;
- case 37: s = "predicate expected"; break;
- case 38: s = "inductive expected"; break;
- case 39: s = "lemma expected"; break;
- case 40: s = "copredicate expected"; break;
- case 41: s = "modifies expected"; break;
- case 42: s = "reads expected"; break;
- case 43: s = "requires expected"; break;
- case 44: s = "lbrace expected"; break;
- case 45: s = "rbrace expected"; break;
- case 46: s = "lbracket expected"; break;
- case 47: s = "rbracket expected"; break;
- case 48: s = "openparen expected"; break;
- case 49: s = "closeparen expected"; break;
- case 50: s = "openAngleBracket expected"; break;
- case 51: s = "closeAngleBracket expected"; break;
- case 52: s = "eq expected"; break;
- case 53: s = "neq expected"; break;
- case 54: s = "neqAlt expected"; break;
- case 55: s = "star expected"; break;
- case 56: s = "notIn expected"; break;
- case 57: s = "ellipsis expected"; break;
- case 58: s = "\"include\" expected"; break;
- case 59: s = "\"abstract\" expected"; break;
- case 60: s = "\"module\" expected"; break;
- case 61: s = "\"refines\" expected"; break;
- case 62: s = "\"import\" expected"; break;
- case 63: s = "\"opened\" expected"; break;
- case 64: s = "\"=\" expected"; break;
- case 65: s = "\"as\" expected"; break;
- case 66: s = "\"default\" expected"; break;
- case 67: s = "\"class\" expected"; break;
- case 68: s = "\"extends\" expected"; break;
- case 69: s = "\"trait\" expected"; break;
- case 70: s = "\"ghost\" expected"; break;
- case 71: s = "\"static\" expected"; break;
- case 72: s = "\"protected\" expected"; break;
- case 73: s = "\"datatype\" expected"; break;
- case 74: s = "\"codatatype\" expected"; break;
- case 75: s = "\"var\" expected"; break;
- case 76: s = "\"newtype\" expected"; break;
- case 77: s = "\"type\" expected"; break;
- case 78: s = "\"iterator\" expected"; break;
- case 79: s = "\"yields\" expected"; break;
- case 80: s = "\"returns\" expected"; break;
- case 81: s = "\"method\" expected"; break;
- case 82: s = "\"colemma\" expected"; break;
- case 83: s = "\"comethod\" expected"; break;
- case 84: s = "\"constructor\" expected"; break;
- case 85: s = "\"free\" expected"; break;
- case 86: s = "\"ensures\" expected"; break;
- case 87: s = "\"yield\" expected"; break;
- case 88: s = "\"`\" expected"; break;
- case 89: s = "\"label\" expected"; break;
- case 90: s = "\"break\" expected"; break;
- case 91: s = "\"where\" expected"; break;
- case 92: s = "\":=\" expected"; break;
- case 93: s = "\"return\" expected"; break;
- case 94: s = "\":|\" expected"; break;
- case 95: s = "\"new\" expected"; break;
- case 96: s = "\"if\" expected"; break;
- case 97: s = "\"while\" expected"; break;
- case 98: s = "\"match\" expected"; break;
- case 99: s = "\"assert\" expected"; break;
- case 100: s = "\"print\" expected"; break;
- case 101: s = "\"forall\" expected"; break;
- case 102: s = "\"parallel\" expected"; break;
- case 103: s = "\"modify\" expected"; break;
- case 104: s = "\"#\" expected"; break;
- case 105: s = "\"<=\" expected"; break;
- case 106: s = "\">=\" expected"; break;
- case 107: s = "\"\\u2264\" expected"; break;
- case 108: s = "\"\\u2265\" expected"; break;
- case 109: s = "\"<==>\" expected"; break;
- case 110: s = "\"\\u21d4\" expected"; break;
- case 111: s = "\"==>\" expected"; break;
- case 112: s = "\"\\u21d2\" expected"; break;
- case 113: s = "\"<==\" expected"; break;
- case 114: s = "\"\\u21d0\" expected"; break;
- case 115: s = "\"&&\" expected"; break;
- case 116: s = "\"\\u2227\" expected"; break;
- case 117: s = "\"||\" expected"; break;
- case 118: s = "\"\\u2228\" expected"; break;
- case 119: s = "\"!\" expected"; break;
- case 120: s = "\"\\u00ac\" expected"; break;
- case 121: s = "\"\\u2200\" expected"; break;
- case 122: s = "\"exists\" expected"; break;
- case 123: s = "\"\\u2203\" expected"; break;
- case 124: s = "\"in\" expected"; break;
- case 125: s = "\"+\" expected"; break;
- case 126: s = "\"-\" expected"; break;
- case 127: s = "\"/\" expected"; break;
- case 128: s = "\"%\" expected"; break;
- case 129: s = "\"false\" expected"; break;
- case 130: s = "\"true\" expected"; break;
- case 131: s = "\"null\" expected"; break;
- case 132: s = "\"this\" expected"; break;
- case 133: s = "\"fresh\" expected"; break;
- case 134: s = "\"old\" expected"; break;
- case 135: s = "\"..\" expected"; break;
- case 136: s = "??? expected"; break;
- case 137: s = "this symbol not expected in SubModuleDecl"; break;
- case 138: s = "invalid SubModuleDecl"; break;
- case 139: s = "this symbol not expected in ClassDecl"; break;
- case 140: s = "this symbol not expected in DatatypeDecl"; break;
- case 141: s = "invalid DatatypeDecl"; break;
- case 142: s = "this symbol not expected in DatatypeDecl"; break;
- case 143: s = "invalid NewtypeDecl"; break;
- case 144: s = "invalid OtherTypeDecl"; break;
- case 145: s = "this symbol not expected in OtherTypeDecl"; break;
- case 146: s = "this symbol not expected in IteratorDecl"; break;
- case 147: s = "invalid IteratorDecl"; break;
- case 148: s = "this symbol not expected in TraitDecl"; break;
- case 149: s = "invalid ClassMemberDecl"; break;
- case 150: s = "this symbol not expected in FieldDecl"; break;
- case 151: s = "invalid FunctionDecl"; break;
- case 152: s = "invalid FunctionDecl"; break;
- case 153: s = "invalid FunctionDecl"; break;
- case 154: s = "invalid FunctionDecl"; break;
- case 155: s = "invalid FunctionDecl"; break;
- case 156: s = "this symbol not expected in MethodDecl"; break;
- case 157: s = "invalid MethodDecl"; break;
- case 158: s = "invalid MethodDecl"; break;
- case 159: s = "invalid FIdentType"; break;
- case 160: s = "this symbol not expected in OldSemi"; break;
- case 161: s = "invalid TypeIdentOptional"; break;
- case 162: s = "invalid TypeAndToken"; break;
- case 163: s = "this symbol not expected in IteratorSpec"; break;
- case 164: s = "invalid IteratorSpec"; break;
- case 165: s = "invalid IteratorSpec"; break;
- case 166: s = "this symbol not expected in MethodSpec"; break;
- case 167: s = "invalid MethodSpec"; break;
- case 168: s = "invalid MethodSpec"; break;
- case 169: s = "invalid FrameExpression"; break;
- case 170: s = "this symbol not expected in FunctionSpec"; break;
- case 171: s = "invalid FunctionSpec"; break;
- case 172: s = "invalid PossiblyWildFrameExpression"; break;
- case 173: s = "invalid PossiblyWildExpression"; break;
- case 174: s = "this symbol not expected in OneStmt"; break;
- case 175: s = "invalid OneStmt"; break;
- case 176: s = "this symbol not expected in OneStmt"; break;
- case 177: s = "invalid OneStmt"; break;
- case 178: s = "invalid AssertStmt"; break;
- case 179: s = "invalid AssumeStmt"; break;
- case 180: s = "invalid UpdateStmt"; break;
- case 181: s = "invalid UpdateStmt"; break;
- case 182: s = "this symbol not expected in VarDeclStatement"; break;
- case 183: s = "invalid IfStmt"; break;
- case 184: s = "invalid IfStmt"; break;
- case 185: s = "invalid WhileStmt"; break;
- case 186: s = "invalid WhileStmt"; break;
- case 187: s = "invalid MatchStmt"; break;
- case 188: s = "invalid ForallStmt"; break;
- case 189: s = "invalid ForallStmt"; break;
- case 190: s = "invalid CalcStmt"; break;
- case 191: s = "invalid ModifyStmt"; break;
- case 192: s = "this symbol not expected in ModifyStmt"; break;
- case 193: s = "invalid ModifyStmt"; break;
- case 194: s = "invalid ReturnStmt"; break;
- case 195: s = "invalid Rhs"; break;
- case 196: s = "invalid Lhs"; break;
- case 197: s = "invalid Guard"; break;
- case 198: s = "this symbol not expected in LoopSpec"; break;
- case 199: s = "this symbol not expected in LoopSpec"; break;
- case 200: s = "this symbol not expected in LoopSpec"; break;
- case 201: s = "invalid LoopSpec"; break;
- case 202: s = "this symbol not expected in CaseStatement"; break;
- case 203: s = "this symbol not expected in CaseStatement"; break;
- case 204: s = "invalid CalcOp"; break;
- case 205: s = "invalid EquivOp"; break;
- case 206: s = "invalid ImpliesOp"; break;
- case 207: s = "invalid ExpliesOp"; break;
- case 208: s = "invalid AndOp"; break;
- case 209: s = "invalid OrOp"; break;
- case 210: s = "invalid NegOp"; break;
- case 211: s = "invalid Forall"; break;
- case 212: s = "invalid Exists"; break;
- case 213: s = "invalid QSep"; break;
- case 214: s = "invalid ImpliesExpliesExpression"; break;
- case 215: s = "invalid LogicalExpression"; break;
- case 216: s = "invalid RelOp"; break;
- case 217: s = "invalid AddOp"; break;
- case 218: s = "invalid UnaryExpression"; break;
- case 219: s = "invalid MulOp"; break;
- case 220: s = "invalid Suffix"; break;
- case 221: s = "invalid Suffix"; break;
- case 222: s = "invalid Suffix"; break;
- case 223: s = "invalid Suffix"; break;
- case 224: s = "invalid LambdaExpression"; break;
- case 225: s = "invalid EndlessExpression"; break;
- case 226: s = "invalid NameSegment"; break;
- case 227: s = "invalid DisplayExpr"; break;
- case 228: s = "invalid MultiSetExpr"; break;
- case 229: s = "invalid ConstAtomExpression"; break;
- case 230: s = "invalid Nat"; break;
- case 231: s = "invalid LambdaArrow"; break;
- case 232: s = "invalid MatchExpression"; break;
- case 233: s = "invalid QuantifierGuts"; break;
- case 234: s = "invalid StmtInExpr"; break;
- case 235: s = "invalid LetExpr"; break;
- case 236: s = "invalid CasePattern"; break;
- case 237: s = "invalid DotSuffix"; break;
+ case 14: s = "iset expected"; break;
+ case 15: s = "multiset expected"; break;
+ case 16: s = "seq expected"; break;
+ case 17: s = "map expected"; break;
+ case 18: s = "imap expected"; break;
+ case 19: s = "charToken expected"; break;
+ case 20: s = "stringToken expected"; break;
+ case 21: s = "colon expected"; break;
+ case 22: s = "comma expected"; break;
+ case 23: s = "verticalbar expected"; break;
+ case 24: s = "doublecolon expected"; break;
+ case 25: s = "boredSmiley expected"; break;
+ case 26: s = "bullet expected"; break;
+ case 27: s = "dot expected"; break;
+ case 28: s = "semi expected"; break;
+ case 29: s = "darrow expected"; break;
+ case 30: s = "arrow expected"; break;
+ case 31: s = "assume expected"; break;
+ case 32: s = "calc expected"; break;
+ case 33: s = "case expected"; break;
+ case 34: s = "then expected"; break;
+ case 35: s = "else expected"; break;
+ case 36: s = "decreases expected"; break;
+ case 37: s = "invariant expected"; break;
+ case 38: s = "function expected"; break;
+ case 39: s = "predicate expected"; break;
+ case 40: s = "inductive expected"; break;
+ case 41: s = "lemma expected"; break;
+ case 42: s = "copredicate expected"; break;
+ case 43: s = "modifies expected"; break;
+ case 44: s = "reads expected"; break;
+ case 45: s = "requires expected"; break;
+ case 46: s = "lbrace expected"; break;
+ case 47: s = "rbrace expected"; break;
+ case 48: s = "lbracket expected"; break;
+ case 49: s = "rbracket expected"; break;
+ case 50: s = "openparen expected"; break;
+ case 51: s = "closeparen expected"; break;
+ case 52: s = "openAngleBracket expected"; break;
+ case 53: s = "closeAngleBracket expected"; break;
+ case 54: s = "eq expected"; break;
+ case 55: s = "neq expected"; break;
+ case 56: s = "neqAlt expected"; break;
+ case 57: s = "star expected"; break;
+ case 58: s = "notIn expected"; break;
+ case 59: s = "ellipsis expected"; break;
+ case 60: s = "\"include\" expected"; break;
+ case 61: s = "\"abstract\" expected"; break;
+ case 62: s = "\"ghost\" expected"; break;
+ case 63: s = "\"static\" expected"; break;
+ case 64: s = "\"protected\" expected"; break;
+ case 65: s = "\"extern\" expected"; break;
+ case 66: s = "\"module\" expected"; break;
+ case 67: s = "\"exclusively\" expected"; break;
+ case 68: s = "\"refines\" expected"; break;
+ case 69: s = "\"import\" expected"; break;
+ case 70: s = "\"opened\" expected"; break;
+ case 71: s = "\"=\" expected"; break;
+ case 72: s = "\"as\" expected"; break;
+ case 73: s = "\"default\" expected"; break;
+ case 74: s = "\"export\" expected"; break;
+ case 75: s = "\"extends\" expected"; break;
+ case 76: s = "\"+\" expected"; break;
+ case 77: s = "\"class\" expected"; break;
+ case 78: s = "\"trait\" expected"; break;
+ case 79: s = "\"datatype\" expected"; break;
+ case 80: s = "\"codatatype\" expected"; break;
+ case 81: s = "\"var\" expected"; break;
+ case 82: s = "\"newtype\" expected"; break;
+ case 83: s = "\"type\" expected"; break;
+ case 84: s = "\"iterator\" expected"; break;
+ case 85: s = "\"yields\" expected"; break;
+ case 86: s = "\"returns\" expected"; break;
+ case 87: s = "\"method\" expected"; break;
+ case 88: s = "\"colemma\" expected"; break;
+ case 89: s = "\"comethod\" expected"; break;
+ case 90: s = "\"constructor\" expected"; break;
+ case 91: s = "\"free\" expected"; break;
+ case 92: s = "\"ensures\" expected"; break;
+ case 93: s = "\"yield\" expected"; break;
+ case 94: s = "\"`\" expected"; break;
+ case 95: s = "\"label\" expected"; break;
+ case 96: s = "\"break\" expected"; break;
+ case 97: s = "\"where\" expected"; break;
+ case 98: s = "\":=\" expected"; break;
+ case 99: s = "\"return\" expected"; break;
+ case 100: s = "\"new\" expected"; break;
+ case 101: s = "\"if\" expected"; break;
+ case 102: s = "\"while\" expected"; break;
+ case 103: s = "\"match\" expected"; break;
+ case 104: s = "\"assert\" expected"; break;
+ case 105: s = "\"print\" expected"; break;
+ case 106: s = "\"forall\" expected"; break;
+ case 107: s = "\"parallel\" expected"; break;
+ case 108: s = "\"modify\" expected"; break;
+ case 109: s = "\"#\" expected"; break;
+ case 110: s = "\"<=\" expected"; break;
+ case 111: s = "\">=\" expected"; break;
+ case 112: s = "\"\\u2264\" expected"; break;
+ case 113: s = "\"\\u2265\" expected"; break;
+ case 114: s = "\"<==>\" expected"; break;
+ case 115: s = "\"\\u21d4\" expected"; break;
+ case 116: s = "\"==>\" expected"; break;
+ case 117: s = "\"\\u21d2\" expected"; break;
+ case 118: s = "\"<==\" expected"; break;
+ case 119: s = "\"\\u21d0\" expected"; break;
+ case 120: s = "\"&&\" expected"; break;
+ case 121: s = "\"\\u2227\" expected"; break;
+ case 122: s = "\"||\" expected"; break;
+ case 123: s = "\"\\u2228\" expected"; break;
+ case 124: s = "\"!\" expected"; break;
+ case 125: s = "\"\\u00ac\" expected"; break;
+ case 126: s = "\"\\u2200\" expected"; break;
+ case 127: s = "\"exists\" expected"; break;
+ case 128: s = "\"\\u2203\" expected"; break;
+ case 129: s = "\"in\" expected"; break;
+ case 130: s = "\"-\" expected"; break;
+ case 131: s = "\"/\" expected"; break;
+ case 132: s = "\"%\" expected"; break;
+ case 133: s = "\"false\" expected"; break;
+ case 134: s = "\"true\" expected"; break;
+ case 135: s = "\"null\" expected"; break;
+ case 136: s = "\"this\" expected"; break;
+ case 137: s = "\"fresh\" expected"; break;
+ case 138: s = "\"old\" expected"; break;
+ case 139: s = "\"..\" expected"; break;
+ case 140: s = "??? expected"; break;
+ case 141: s = "invalid TopDecl"; break;
+ case 142: s = "invalid DeclModifier"; break;
+ case 143: s = "this symbol not expected in SubModuleDecl"; break;
+ case 144: s = "invalid SubModuleDecl"; break;
+ case 145: s = "this symbol not expected in ClassDecl"; break;
+ case 146: s = "this symbol not expected in DatatypeDecl"; break;
+ case 147: s = "invalid DatatypeDecl"; break;
+ case 148: s = "this symbol not expected in DatatypeDecl"; break;
+ case 149: s = "invalid NewtypeDecl"; break;
+ case 150: s = "invalid OtherTypeDecl"; break;
+ case 151: s = "this symbol not expected in OtherTypeDecl"; break;
+ case 152: s = "this symbol not expected in IteratorDecl"; break;
+ case 153: s = "invalid IteratorDecl"; break;
+ case 154: s = "this symbol not expected in TraitDecl"; break;
+ case 155: s = "invalid ClassMemberDecl"; break;
+ case 156: s = "this symbol not expected in FieldDecl"; break;
+ case 157: s = "invalid FunctionDecl"; break;
+ case 158: s = "invalid FunctionDecl"; break;
+ case 159: s = "invalid FunctionDecl"; break;
+ case 160: s = "invalid FunctionDecl"; break;
+ case 161: s = "invalid FunctionDecl"; break;
+ case 162: s = "this symbol not expected in MethodDecl"; break;
+ case 163: s = "invalid MethodDecl"; break;
+ case 164: s = "invalid MethodDecl"; break;
+ case 165: s = "invalid FIdentType"; break;
+ case 166: s = "this symbol not expected in OldSemi"; break;
+ case 167: s = "invalid TypeIdentOptional"; break;
+ case 168: s = "invalid TypeAndToken"; break;
+ case 169: s = "this symbol not expected in IteratorSpec"; break;
+ case 170: s = "invalid IteratorSpec"; break;
+ case 171: s = "invalid IteratorSpec"; break;
+ case 172: s = "this symbol not expected in MethodSpec"; break;
+ case 173: s = "invalid MethodSpec"; break;
+ case 174: s = "invalid MethodSpec"; break;
+ case 175: s = "invalid FrameExpression"; break;
+ case 176: s = "this symbol not expected in FunctionSpec"; break;
+ case 177: s = "invalid FunctionSpec"; break;
+ case 178: s = "invalid PossiblyWildFrameExpression"; break;
+ case 179: s = "invalid PossiblyWildExpression"; break;
+ case 180: s = "this symbol not expected in OneStmt"; break;
+ case 181: s = "invalid OneStmt"; break;
+ case 182: s = "this symbol not expected in OneStmt"; break;
+ case 183: s = "invalid OneStmt"; break;
+ case 184: s = "invalid AssertStmt"; break;
+ case 185: s = "invalid AssumeStmt"; break;
+ case 186: s = "invalid UpdateStmt"; break;
+ case 187: s = "invalid UpdateStmt"; break;
+ case 188: s = "this symbol not expected in VarDeclStatement"; break;
+ case 189: s = "invalid VarDeclStatement"; break;
+ case 190: s = "invalid VarDeclStatement"; break;
+ case 191: s = "invalid IfStmt"; break;
+ case 192: s = "invalid IfStmt"; break;
+ case 193: s = "invalid WhileStmt"; break;
+ case 194: s = "invalid WhileStmt"; break;
+ case 195: s = "invalid MatchStmt"; break;
+ case 196: s = "invalid ForallStmt"; break;
+ case 197: s = "invalid ForallStmt"; break;
+ case 198: s = "invalid CalcStmt"; break;
+ case 199: s = "invalid ModifyStmt"; break;
+ case 200: s = "this symbol not expected in ModifyStmt"; break;
+ case 201: s = "invalid ModifyStmt"; break;
+ case 202: s = "invalid ReturnStmt"; break;
+ case 203: s = "invalid Rhs"; break;
+ case 204: s = "invalid Lhs"; break;
+ case 205: s = "invalid CasePattern"; break;
+ case 206: s = "invalid AlternativeBlock"; break;
+ case 207: s = "invalid Guard"; break;
+ case 208: s = "this symbol not expected in LoopSpec"; break;
+ case 209: s = "this symbol not expected in LoopSpec"; break;
+ case 210: s = "this symbol not expected in LoopSpec"; break;
+ case 211: s = "invalid LoopSpec"; break;
+ case 212: s = "invalid CaseStatement"; break;
+ case 213: s = "this symbol not expected in CaseStatement"; break;
+ case 214: s = "this symbol not expected in CaseStatement"; break;
+ case 215: s = "invalid CalcOp"; break;
+ case 216: s = "invalid EquivOp"; break;
+ case 217: s = "invalid ImpliesOp"; break;
+ case 218: s = "invalid ExpliesOp"; break;
+ case 219: s = "invalid AndOp"; break;
+ case 220: s = "invalid OrOp"; break;
+ case 221: s = "invalid NegOp"; break;
+ case 222: s = "invalid Forall"; break;
+ case 223: s = "invalid Exists"; break;
+ case 224: s = "invalid QSep"; break;
+ case 225: s = "invalid ImpliesExpliesExpression"; break;
+ case 226: s = "invalid LogicalExpression"; break;
+ case 227: s = "invalid RelOp"; break;
+ case 228: s = "invalid AddOp"; break;
+ case 229: s = "invalid UnaryExpression"; break;
+ case 230: s = "invalid MulOp"; break;
+ case 231: s = "invalid Suffix"; break;
+ case 232: s = "invalid Suffix"; break;
+ case 233: s = "invalid Suffix"; break;
+ case 234: s = "invalid Suffix"; break;
+ case 235: s = "invalid Suffix"; break;
+ case 236: s = "invalid LambdaExpression"; break;
+ case 237: s = "invalid EndlessExpression"; break;
+ case 238: s = "invalid NameSegment"; break;
+ case 239: s = "invalid DisplayExpr"; break;
+ case 240: s = "invalid MultiSetExpr"; break;
+ case 241: s = "invalid ConstAtomExpression"; break;
+ case 242: s = "invalid Nat"; break;
+ case 243: s = "invalid LambdaArrow"; break;
+ case 244: s = "invalid MatchExpression"; break;
+ case 245: s = "invalid QuantifierGuts"; break;
+ case 246: s = "invalid StmtInExpr"; break;
+ case 247: s = "invalid LetExpr"; break;
+ case 248: s = "invalid CaseExpression"; break;
+ case 249: s = "invalid MemberBindingUpdate"; break;
+ case 250: s = "invalid DotSuffix"; break;
default: s = "error " + n; break;
}
return s;
}
- public void SemErr(IToken/*!*/ tok, string/*!*/ msg) { // semantic errors
+ public void SemErr(IToken tok, string msg) { // semantic errors
Contract.Requires(tok != null);
Contract.Requires(msg != null);
- SemErr(tok.filename, tok.line, tok.col, msg);
+ ErrorCount++;
+ Reporting.Error(MessageSource.Parser, tok, msg);
}
- public virtual void SemErr(string filename, int line, int col, string/*!*/ msg) {
+ public void SemErr(string filename, int line, int col, string msg) {
Contract.Requires(msg != null);
- errorStream.WriteLine(errMsgFormat, filename, line, col, msg);
- count++;
+ ErrorCount++;
+ Reporting.Error(MessageSource.Parser, filename, line, col, msg);
}
- public void Warning(IToken/*!*/ tok, string/*!*/ msg) { // warnings
+ public void Warning(IToken tok, string msg) {
Contract.Requires(tok != null);
Contract.Requires(msg != null);
- Warning(tok.filename, tok.line, tok.col, msg);
- }
-
- public virtual void Warning(string filename, int line, int col, string msg) {
- Contract.Requires(msg != null);
- errorStream.WriteLine(warningMsgFormat, filename, line, col, msg);
+ Reporting.Warning(MessageSource.Parser, tok, msg);
}
} // Errors
@@ -4602,6 +5020,4 @@ public class Errors {
public class FatalError: Exception {
public FatalError(string m): base(m) {}
}
-
-
} \ No newline at end of file
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index bf42c71a..0ba6f439 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -1,1988 +1,2109 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Numerics;
-using System.Linq;
-using Bpl = Microsoft.Boogie;
-
-namespace Microsoft.Dafny {
- public class Printer {
- TextWriter wr;
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Numerics;
+using System.Linq;
+using Bpl = Microsoft.Boogie;
+
+namespace Microsoft.Dafny {
+ public class Printer {
+ TextWriter wr;
DafnyOptions.PrintModes printMode;
-
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(wr!=null);
- }
-
- public Printer(TextWriter wr, DafnyOptions.PrintModes printMode = DafnyOptions.PrintModes.Everything) {
- Contract.Requires(wr != null);
- this.wr = wr;
- this.printMode = printMode;
- }
-
- public static string ExprToString(Expression expr)
- {
- Contract.Requires(expr != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintExpression(expr, false);
- return wr.ToString();
- }
- }
-
- public static string GuardToString(Expression expr) {
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintGuard(expr);
- return wr.ToString();
- }
- }
-
- public static string ExtendedExprToString(Expression expr) {
- Contract.Requires(expr != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintExtendedExpr(expr, 0, true, false);
- return wr.ToString();
- }
- }
-
- public static string FrameExprListToString(List<FrameExpression> fexprs) {
- Contract.Requires(fexprs != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintFrameExpressionList(fexprs);
- return wr.ToString();
- }
- }
-
- public static string StatementToString(Statement stmt) {
- Contract.Requires(stmt != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintStatement(stmt, 0);
- return ToStringWithoutNewline(wr);
- }
- }
-
- public static string IteratorClassToString(IteratorDecl iter) {
- Contract.Requires(iter != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintIteratorClass(iter, 0, null);
- return ToStringWithoutNewline(wr);
- }
- }
-
- public static string IteratorSignatureToString(IteratorDecl iter) {
- Contract.Requires(iter != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintIteratorSignature(iter, 0);
- return ToStringWithoutNewline(wr);
- }
- }
-
- public static string FunctionSignatureToString(Function f) {
- Contract.Requires(f != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintFunction(f, 0, true);
- return ToStringWithoutNewline(wr);
- }
- }
-
- public static string MethodSignatureToString(Method m) {
- Contract.Requires(m != null);
- using (var wr = new System.IO.StringWriter()) {
- var pr = new Printer(wr);
- pr.PrintMethod(m, 0, true);
- return ToStringWithoutNewline(wr);
- }
- }
-
- public static string ToStringWithoutNewline(System.IO.StringWriter wr) {
- Contract.Requires(wr != null);
- var sb = wr.GetStringBuilder();
- var len = sb.Length;
- while (len > 0 && (sb[len - 1] == '\n' || sb[len - 1] == '\r')) {
- len--;
- }
- return sb.ToString(0, len);
- }
-
- public void PrintProgram(Program prog) {
+ bool afterResolver;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant()
+ {
+ Contract.Invariant(wr!=null);
+ }
+
+ public Printer(TextWriter wr, DafnyOptions.PrintModes printMode = DafnyOptions.PrintModes.Everything) {
+ Contract.Requires(wr != null);
+ this.wr = wr;
+ this.printMode = printMode;
+ }
+
+ public static string ExprToString(Expression expr)
+ {
+ Contract.Requires(expr != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintExpression(expr, false);
+ return wr.ToString();
+ }
+ }
+
+ public static string GuardToString(bool isExistentialGuard, Expression expr) {
+ Contract.Requires(!isExistentialGuard || (expr is ExistsExpr && ((ExistsExpr)expr).Range == null));
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintGuard(isExistentialGuard, expr);
+ return wr.ToString();
+ }
+ }
+
+ public static string ExtendedExprToString(Expression expr) {
+ Contract.Requires(expr != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintExtendedExpr(expr, 0, true, false);
+ return wr.ToString();
+ }
+ }
+
+ public static string FrameExprListToString(List<FrameExpression> fexprs) {
+ Contract.Requires(fexprs != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintFrameExpressionList(fexprs);
+ return wr.ToString();
+ }
+ }
+
+ public static string StatementToString(Statement stmt) {
+ Contract.Requires(stmt != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintStatement(stmt, 0);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string IteratorClassToString(IteratorDecl iter) {
+ Contract.Requires(iter != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintIteratorClass(iter, 0, null);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string IteratorSignatureToString(IteratorDecl iter) {
+ Contract.Requires(iter != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintIteratorSignature(iter, 0);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string FunctionSignatureToString(Function f) {
+ Contract.Requires(f != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintFunction(f, 0, true);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string MethodSignatureToString(Method m) {
+ Contract.Requires(m != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintMethod(m, 0, true);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string OneAttributeToString(Attributes a, string nameSubstitution = null) {
+ Contract.Requires(a != null);
+ using (var wr = new System.IO.StringWriter()) {
+ var pr = new Printer(wr);
+ pr.PrintOneAttribute(a, nameSubstitution);
+ return ToStringWithoutNewline(wr);
+ }
+ }
+
+ public static string ToStringWithoutNewline(System.IO.StringWriter wr) {
+ Contract.Requires(wr != null);
+ var sb = wr.GetStringBuilder();
+ var len = sb.Length;
+ while (len > 0 && (sb[len - 1] == '\n' || sb[len - 1] == '\r')) {
+ len--;
+ }
+ return sb.ToString(0, len);
+ }
+
+ public void PrintProgram(Program prog, bool afterResolver) {
Contract.Requires(prog != null);
- if (Bpl.CommandLineOptions.Clo.ShowEnv != Bpl.CommandLineOptions.ShowEnvironment.Never) {
- wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Version);
- wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Environment);
- }
- wr.WriteLine("// {0}", prog.Name);
- if (DafnyOptions.O.DafnyPrintResolvedFile != null) {
- wr.WriteLine();
- wr.WriteLine("/*");
- PrintModuleDefinition(prog.BuiltIns.SystemModule, 0, Path.GetFullPath(DafnyOptions.O.DafnyPrintResolvedFile));
- wr.WriteLine("*/");
- }
- wr.WriteLine();
- PrintCallGraph(prog.DefaultModuleDef, 0);
- PrintTopLevelDecls(prog.DefaultModuleDef.TopLevelDecls, 0, Path.GetFullPath(prog.FullName));
- wr.Flush();
- }
-
- public void PrintCallGraph(ModuleDefinition module, int indent) {
- Contract.Requires(module != null);
- Contract.Requires(0 <= indent);
- if (DafnyOptions.O.DafnyPrintResolvedFile != null) {
- // print call graph
- Indent(indent); wr.WriteLine("/* CALL GRAPH for module {0}:", module.Name);
- var SCCs = module.CallGraph.TopologicallySortedComponents();
- SCCs.Reverse();
- foreach (var clbl in SCCs) {
- Indent(indent); wr.WriteLine(" * SCC at height {0}:", module.CallGraph.GetSCCRepresentativeId(clbl));
- var r = module.CallGraph.GetSCC(clbl);
- foreach (var m in r) {
- Indent(indent); wr.WriteLine(" * {0}", m.NameRelativeToModule);
- }
- }
- Indent(indent); wr.WriteLine(" */");
- }
- }
-
- public void PrintTopLevelDecls(List<TopLevelDecl> decls, int indent, string fileBeingPrinted) {
- Contract.Requires(decls!= null);
- int i = 0;
- foreach (TopLevelDecl d in decls) {
- Contract.Assert(d != null);
- if (PrintModeSkipGeneral(d.tok, fileBeingPrinted)) { continue; }
- if (d is OpaqueTypeDecl) {
- var at = (OpaqueTypeDecl)d;
- if (i++ != 0) { wr.WriteLine(); }
- Indent(indent);
- PrintClassMethodHelper("type", at.Attributes, at.Name, new List<TypeParameter>());
- wr.Write(EqualitySupportSuffix(at.EqualitySupport));
- wr.WriteLine();
- } else if (d is NewtypeDecl) {
- var dd = (NewtypeDecl)d;
- if (i++ != 0) { wr.WriteLine(); }
- Indent(indent);
- PrintClassMethodHelper("newtype", dd.Attributes, dd.Name, new List<TypeParameter>());
- wr.Write(" = ");
- if (dd.Var == null) {
- PrintType(dd.BaseType);
- } else {
- wr.Write(dd.Var.DisplayName);
- if (!(dd.Var.Type is TypeProxy) || DafnyOptions.O.DafnyPrintResolvedFile != null) {
- wr.Write(": ");
- PrintType(dd.BaseType);
- }
- wr.Write(" | ");
- PrintExpression(dd.Constraint, true);
- }
- wr.WriteLine();
- } else if (d is TypeSynonymDecl) {
- var syn = (TypeSynonymDecl)d;
- if (i++ != 0) { wr.WriteLine(); }
- Indent(indent);
- PrintClassMethodHelper("type", syn.Attributes, syn.Name, syn.TypeArgs);
- wr.Write(" = ");
- PrintType(syn.Rhs);
- wr.WriteLine();
- } else if (d is DatatypeDecl) {
- if (i++ != 0) { wr.WriteLine(); }
- PrintDatatype((DatatypeDecl)d, indent);
- } else if (d is IteratorDecl) {
- var iter = (IteratorDecl)d;
- PrintIteratorSignature(iter, indent);
-
- if (iter.Body != null) {
- Indent(indent);
- PrintStatement(iter.Body, indent);
- wr.WriteLine();
- }
-
- if (DafnyOptions.O.DafnyPrintResolvedFile != null) {
- // also print the members that were created as part of the interpretation of the iterator
- Contract.Assert(iter.Members.Count != 0); // filled in during resolution
- wr.WriteLine("/*---------- iterator members ----------");
- PrintIteratorClass(iter, indent, fileBeingPrinted);
- wr.WriteLine("---------- iterator members ----------*/");
- }
-
- } else if (d is ClassDecl) {
- ClassDecl cl = (ClassDecl)d;
- if (!cl.IsDefaultClass) {
- if (i++ != 0) { wr.WriteLine(); }
- PrintClass(cl, indent, fileBeingPrinted);
- } else if (cl.Members.Count == 0) {
- // print nothing
- } else {
- if (i++ != 0) { wr.WriteLine(); }
- PrintMembers(cl.Members, indent, fileBeingPrinted);
- }
-
+ this.afterResolver = afterResolver;
+ if (Bpl.CommandLineOptions.Clo.ShowEnv != Bpl.CommandLineOptions.ShowEnvironment.Never) {
+ wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Version);
+ wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Environment);
+ }
+ wr.WriteLine("// {0}", prog.Name);
+ if (DafnyOptions.O.DafnyPrintResolvedFile != null && DafnyOptions.O.PrintMode == DafnyOptions.PrintModes.Everything) {
+ wr.WriteLine();
+ wr.WriteLine("/*");
+ PrintModuleDefinition(prog.BuiltIns.SystemModule, 0, Path.GetFullPath(DafnyOptions.O.DafnyPrintResolvedFile));
+ wr.WriteLine("*/");
+ }
+ wr.WriteLine();
+ PrintCallGraph(prog.DefaultModuleDef, 0);
+ PrintTopLevelDecls(prog.DefaultModuleDef.TopLevelDecls, 0, Path.GetFullPath(prog.FullName));
+ wr.Flush();
+ }
+
+ public void PrintCallGraph(ModuleDefinition module, int indent) {
+ Contract.Requires(module != null);
+ Contract.Requires(0 <= indent);
+ if (DafnyOptions.O.DafnyPrintResolvedFile != null && DafnyOptions.O.PrintMode == DafnyOptions.PrintModes.Everything) {
+ // print call graph
+ Indent(indent); wr.WriteLine("/* CALL GRAPH for module {0}:", module.Name);
+ var SCCs = module.CallGraph.TopologicallySortedComponents();
+ SCCs.Reverse();
+ foreach (var clbl in SCCs) {
+ Indent(indent); wr.WriteLine(" * SCC at height {0}:", module.CallGraph.GetSCCRepresentativeId(clbl));
+ var r = module.CallGraph.GetSCC(clbl);
+ foreach (var m in r) {
+ Indent(indent); wr.WriteLine(" * {0}", m.NameRelativeToModule);
+ }
+ }
+ Indent(indent); wr.WriteLine(" */");
+ }
+ }
+
+ public void PrintTopLevelDecls(List<TopLevelDecl> decls, int indent, string fileBeingPrinted) {
+ Contract.Requires(decls!= null);
+ int i = 0;
+ foreach (TopLevelDecl d in decls) {
+ Contract.Assert(d != null);
+ if (PrintModeSkipGeneral(d.tok, fileBeingPrinted)) { continue; }
+ if (d is OpaqueTypeDecl) {
+ var at = (OpaqueTypeDecl)d;
+ if (i++ != 0) { wr.WriteLine(); }
+ Indent(indent);
+ PrintClassMethodHelper("type", at.Attributes, at.Name, new List<TypeParameter>());
+ wr.Write(EqualitySupportSuffix(at.EqualitySupport));
+ wr.WriteLine();
+ } else if (d is NewtypeDecl) {
+ var dd = (NewtypeDecl)d;
+ if (i++ != 0) { wr.WriteLine(); }
+ Indent(indent);
+ PrintClassMethodHelper("newtype", dd.Attributes, dd.Name, new List<TypeParameter>());
+ wr.Write(" = ");
+ if (dd.Var == null) {
+ PrintType(dd.BaseType);
+ } else {
+ wr.Write(dd.Var.DisplayName);
+ if (!(dd.Var.Type is TypeProxy) || DafnyOptions.O.DafnyPrintResolvedFile != null) {
+ wr.Write(": ");
+ PrintType(dd.BaseType);
+ }
+ wr.Write(" | ");
+ PrintExpression(dd.Constraint, true);
+ }
+ wr.WriteLine();
+ } else if (d is TypeSynonymDecl) {
+ var syn = (TypeSynonymDecl)d;
+ if (i++ != 0) { wr.WriteLine(); }
+ Indent(indent);
+ PrintClassMethodHelper("type", syn.Attributes, syn.Name, syn.TypeArgs);
+ wr.Write(" = ");
+ PrintType(syn.Rhs);
+ wr.WriteLine();
+ } else if (d is DatatypeDecl) {
+ if (i++ != 0) { wr.WriteLine(); }
+ PrintDatatype((DatatypeDecl)d, indent);
+ } else if (d is IteratorDecl) {
+ var iter = (IteratorDecl)d;
+ PrintIteratorSignature(iter, indent);
+
+ if (iter.Body != null) {
+ Indent(indent);
+ PrintStatement(iter.Body, indent);
+ wr.WriteLine();
+ }
+
+ if (DafnyOptions.O.DafnyPrintResolvedFile != null) {
+ // also print the members that were created as part of the interpretation of the iterator
+ Contract.Assert(iter.Members.Count != 0); // filled in during resolution
+ wr.WriteLine("/*---------- iterator members ----------");
+ PrintIteratorClass(iter, indent, fileBeingPrinted);
+ wr.WriteLine("---------- iterator members ----------*/");
+ }
+
+ } else if (d is ClassDecl) {
+ ClassDecl cl = (ClassDecl)d;
+ if (!cl.IsDefaultClass) {
+ if (i++ != 0) { wr.WriteLine(); }
+ PrintClass(cl, indent, fileBeingPrinted);
+ } else if (cl.Members.Count == 0) {
+ // print nothing
+ } else {
+ if (i++ != 0) { wr.WriteLine(); }
+ PrintMembers(cl.Members, indent, fileBeingPrinted);
+ }
+
} else if (d is ModuleDecl) {
- wr.WriteLine();
- Indent(indent);
- if (d is LiteralModuleDecl) {
- ModuleDefinition module = ((LiteralModuleDecl)d).ModuleDef;
- PrintModuleDefinition(module, indent, fileBeingPrinted);
- } else if (d is AliasModuleDecl) {
- wr.Write("import"); if (((AliasModuleDecl)d).Opened) wr.Write(" opened");
- wr.Write(" {0} ", ((AliasModuleDecl)d).Name);
- wr.WriteLine("= {0}", Util.Comma(".", ((AliasModuleDecl)d).Path, id => id.val));
- } else if (d is ModuleFacadeDecl) {
- wr.Write("import"); if (((ModuleFacadeDecl)d).Opened) wr.Write(" opened");
- wr.Write(" {0} ", ((ModuleFacadeDecl)d).Name);
+ wr.WriteLine();
+ Indent(indent);
+ if (d is LiteralModuleDecl) {
+ ModuleDefinition module = ((LiteralModuleDecl)d).ModuleDef;
+ PrintModuleDefinition(module, indent, fileBeingPrinted);
+ } else if (d is AliasModuleDecl) {
+ wr.Write("import"); if (((AliasModuleDecl)d).Opened) wr.Write(" opened");
+ wr.Write(" {0} ", ((AliasModuleDecl)d).Name);
+ wr.WriteLine("= {0}", Util.Comma(".", ((AliasModuleDecl)d).Path, id => id.val));
+ } else if (d is ModuleFacadeDecl) {
+ wr.Write("import"); if (((ModuleFacadeDecl)d).Opened) wr.Write(" opened");
+ wr.Write(" {0} ", ((ModuleFacadeDecl)d).Name);
wr.WriteLine("as {0}", Util.Comma(".", ((ModuleFacadeDecl)d).Path, id => id.val));
- }
-
- } else {
- Contract.Assert(false); // unexpected TopLevelDecl
- }
- }
- }
-
- void PrintModuleDefinition(ModuleDefinition module, int indent, string fileBeingPrinted) {
- Contract.Requires(module != null);
- Contract.Requires(0 <= indent);
- if (module.IsAbstract) {
- wr.Write("abstract ");
- }
- wr.Write("module");
- PrintAttributes(module.Attributes);
- wr.Write(" {0} ", module.Name);
- if (module.RefinementBaseName != null) {
- wr.Write("refines {0} ", Util.Comma(".", module.RefinementBaseName, id => id.val));
- }
- if (module.TopLevelDecls.Count == 0) {
- wr.WriteLine("{ }");
- } else {
- wr.WriteLine("{");
- PrintCallGraph(module, indent + IndentAmount);
- PrintTopLevelDecls(module.TopLevelDecls, indent + IndentAmount, fileBeingPrinted);
- Indent(indent);
- wr.WriteLine("}");
- }
- }
-
- void PrintIteratorSignature(IteratorDecl iter, int indent) {
- Indent(indent);
- PrintClassMethodHelper("iterator", iter.Attributes, iter.Name, iter.TypeArgs);
- if (iter.SignatureIsOmitted) {
- wr.WriteLine(" ...");
- } else {
- PrintFormals(iter.Ins);
- if (iter.Outs.Count != 0) {
- if (iter.Ins.Count + iter.Outs.Count <= 3) {
- wr.Write(" yields ");
- } else {
- wr.WriteLine();
- Indent(indent + 2 * IndentAmount);
- wr.Write("yields ");
- }
- PrintFormals(iter.Outs);
- }
- wr.WriteLine();
- }
-
- int ind = indent + IndentAmount;
- PrintSpec("requires", iter.Requires, ind);
- if (iter.Reads.Expressions != null) {
- PrintFrameSpecLine("reads", iter.Reads.Expressions, ind, iter.Reads.HasAttributes() ? iter.Reads.Attributes : null);
- }
- if (iter.Modifies.Expressions != null) {
- PrintFrameSpecLine("modifies", iter.Modifies.Expressions, ind, iter.Modifies.HasAttributes() ? iter.Modifies.Attributes : null);
- }
- PrintSpec("yield requires", iter.YieldRequires, ind);
- PrintSpec("yield ensures", iter.YieldEnsures, ind);
- PrintSpec("ensures", iter.Ensures, ind);
- PrintDecreasesSpec(iter.Decreases, ind);
- }
-
- private void PrintIteratorClass(IteratorDecl iter, int indent, string fileBeingPrinted) {
- PrintClassMethodHelper("class", null, iter.Name, iter.TypeArgs);
- wr.WriteLine(" {");
- PrintMembers(iter.Members, indent + IndentAmount, fileBeingPrinted);
- Indent(indent); wr.WriteLine("}");
- }
-
- public void PrintClass(ClassDecl c, int indent, string fileBeingPrinted) {
- Contract.Requires(c != null);
- Indent(indent);
- PrintClassMethodHelper((c is TraitDecl) ? "trait" : "class", c.Attributes, c.Name, c.TypeArgs);
- string sep = " extends ";
- foreach (var trait in c.TraitsTyp) {
- wr.Write(sep);
- PrintType(trait);
- sep = ", ";
- }
- if (c.Members.Count == 0) {
- wr.WriteLine(" { }");
- } else {
- wr.WriteLine(" {");
- PrintMembers(c.Members, indent + IndentAmount, fileBeingPrinted);
- Indent(indent);
- wr.WriteLine("}");
- }
- }
-
- public void PrintMembers(List<MemberDecl> members, int indent, string fileBeingPrinted)
- {
- Contract.Requires(members != null);
-
- int state = 0; // 0 - no members yet; 1 - previous member was a field; 2 - previous member was non-field
- foreach (MemberDecl m in members) {
- if (PrintModeSkipGeneral(m.tok, fileBeingPrinted)) { continue; }
- if (m is Method) {
- if (state != 0) { wr.WriteLine(); }
- PrintMethod((Method)m, indent, false);
- var com = m as FixpointLemma;
- if (com != null && com.PrefixLemma != null) {
- Indent(indent); wr.WriteLine("/***");
- PrintMethod(com.PrefixLemma, indent, false);
- Indent(indent); wr.WriteLine("***/");
- }
- state = 2;
- } else if (m is Field) {
- if (state == 2) { wr.WriteLine(); }
- PrintField((Field)m, indent);
- state = 1;
- } else if (m is Function) {
- if (state != 0) { wr.WriteLine(); }
- PrintFunction((Function)m, indent, false);
- var fixp = m as FixpointPredicate;
- if (fixp != null && fixp.PrefixPredicate != null) {
- Indent(indent); wr.WriteLine("/***");
- PrintFunction(fixp.PrefixPredicate, indent, false);
- Indent(indent); wr.WriteLine("***/");
- }
- state = 2;
- } else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member
- }
- }
- }
-
- /// <summary>
- /// Prints no space before "kind", but does print a space before "attrs" and "name".
- /// </summary>
- void PrintClassMethodHelper(string kind, Attributes attrs, string name, List<TypeParameter> typeArgs) {
- Contract.Requires(kind != null);
- Contract.Requires(name != null);
- Contract.Requires(typeArgs != null);
- if (kind.Length != 0) {
- wr.Write(kind);
- }
-
- PrintAttributes(attrs);
-
- wr.Write(" {0}", name);
- PrintTypeParams(typeArgs);
- }
-
- private void PrintTypeParams(List<TypeParameter> typeArgs) {
- Contract.Requires(typeArgs != null);
- if (typeArgs.Count != 0) {
- wr.Write("<" +
- Util.Comma(", ", typeArgs,
- tp => tp.Name + EqualitySupportSuffix(tp.EqualitySupport))
- + ">");
- }
+ } else if (d is ModuleExportDecl) {
+ ModuleExportDecl e = (ModuleExportDecl)d;
+ if (e.IsDefault) wr.Write("default ");
+ wr.Write("export {0}", e.Name);
+ if (e.Extends.Count > 0) wr.Write(" extends {0}", Util.Comma(e.Extends, id => id));
+ PrintModuleExportDecl(e, indent, fileBeingPrinted);
+ }
+
+ } else {
+ Contract.Assert(false); // unexpected TopLevelDecl
+ }
+ }
}
- private void PrintTypeInstantiation(List<Type> typeArgs) {
- Contract.Requires(typeArgs == null || typeArgs.Count != 0);
- if (typeArgs != null) {
- wr.Write("<{0}>", Util.Comma(",", typeArgs, ty => ty.ToString()));
- }
- }
-
- public void PrintDatatype(DatatypeDecl dt, int indent) {
- Contract.Requires(dt != null);
- Indent(indent);
- PrintClassMethodHelper(dt is IndDatatypeDecl ? "datatype" : "codatatype", dt.Attributes, dt.Name, dt.TypeArgs);
- wr.Write(" =");
- string sep = "";
- foreach (DatatypeCtor ctor in dt.Ctors) {
- wr.Write(sep);
- PrintClassMethodHelper("", ctor.Attributes, ctor.Name, new List<TypeParameter>());
- if (ctor.Formals.Count != 0) {
- PrintFormals(ctor.Formals);
- }
- sep = " |";
- }
- wr.WriteLine();
- }
-
- /// <summary>
- /// Prints a space before each attribute.
- /// </summary>
- public void PrintAttributes(Attributes a) {
- if (a != null) {
- PrintAttributes(a.Prev);
-
- wr.Write(" {{:{0}", a.Name);
- if (a.Args != null)
- {
- PrintAttributeArgs(a.Args, false);
- }
+ void PrintModuleExportDecl(ModuleExportDecl m, int indent, string fileBeingPrinted) {
+ ModuleSignature sig = m.Signature;
+ if (sig == null) {
+ wr.Write(" {");
+ // has been resolved yet, just print the strings
+ wr.Write("{0}", Util.Comma(m.Exports, id => id.Name));
wr.Write("}");
- }
- }
-
- public void PrintAttributeArgs(List<Expression> args, bool isFollowedBySemicolon) {
- Contract.Requires(args != null);
- string prefix = " ";
- foreach (var arg in args) {
- Contract.Assert(arg != null);
- wr.Write(prefix);
- prefix = ", ";
- PrintExpression(arg, isFollowedBySemicolon);
- }
- }
-
- public void PrintField(Field field, int indent) {
- Contract.Requires(field != null);
- Indent(indent);
- if (field.IsGhost) {
- wr.Write("ghost ");
- }
- wr.Write("var");
- PrintAttributes(field.Attributes);
- wr.Write(" {0}: ", field.Name);
- PrintType(field.Type);
- if (field.IsUserMutable) {
- // nothing more to say
- } else if (field.IsMutable) {
- wr.Write(" // non-assignable");
} else {
- wr.Write(" // immutable");
- }
- wr.WriteLine();
- }
-
- public void PrintFunction(Function f, int indent, bool printSignatureOnly) {
- Contract.Requires(f != null);
-
- if (PrintModeSkipFunctionOrMethod(f.IsGhost, f.Attributes, f.Name)) { return; }
- var isPredicate = f is Predicate || f is PrefixPredicate;
- Indent(indent);
- string k = isPredicate ? "predicate" : f is InductivePredicate ? "inductive predicate" : f is CoPredicate ? "copredicate" : "function";
- if (f.IsProtected) { k = "protected " + k; }
- if (f.HasStaticKeyword) { k = "static " + k; }
- if (!f.IsGhost) { k += " method"; }
- PrintClassMethodHelper(k, f.Attributes, f.Name, f.TypeArgs);
- if (f.SignatureIsOmitted) {
- wr.WriteLine(" ...");
- } else {
- PrintFormals(f.Formals, f.Name);
- if (!isPredicate) {
- wr.Write(": ");
- PrintType(f.ResultType);
- }
- wr.WriteLine();
- }
-
- int ind = indent + IndentAmount;
- PrintSpec("requires", f.Req, ind);
- PrintFrameSpecLine("reads", f.Reads, ind, null);
- PrintSpec("ensures", f.Ens, ind);
- PrintDecreasesSpec(f.Decreases, ind);
- if (f.Body != null && !printSignatureOnly) {
- Indent(indent);
- wr.WriteLine("{");
- PrintExtendedExpr(f.Body, ind, true, false);
- Indent(indent);
- wr.WriteLine("}");
- }
- }
-
- // ----------------------------- PrintMethod -----------------------------
-
- const int IndentAmount = 2; // The amount of indent for each new scope
- const string BunchaSpaces = " ";
- void Indent(int amount)
- {
- Contract.Requires(0 <= amount);
-
- while (0 < amount) {
- wr.Write(BunchaSpaces.Substring(0, amount));
- amount -= BunchaSpaces.Length;
- }
- }
-
- private bool PrintModeSkipFunctionOrMethod(bool IsGhost, Attributes attributes, string name)
- {
- if (printMode == DafnyOptions.PrintModes.NoGhost && IsGhost)
- { return true; }
- if (printMode == DafnyOptions.PrintModes.NoIncludes || printMode == DafnyOptions.PrintModes.NoGhost)
- {
- bool verify = true;
- if (Attributes.ContainsBool(attributes, "verify", ref verify) && !verify)
- { return true; }
- if (name.Contains("INTERNAL") || name.StartsWith("reveal_"))
- { return true; }
- }
- return false;
- }
-
- private bool PrintModeSkipGeneral(Bpl.IToken tok, string fileBeingPrinted)
- {
- return (printMode == DafnyOptions.PrintModes.NoIncludes || printMode == DafnyOptions.PrintModes.NoGhost)
- && (tok.filename != null && fileBeingPrinted != null && Path.GetFullPath(tok.filename) != fileBeingPrinted);
+ wr.WriteLine(" {");
+ // print the decls and members in the module
+ List<TopLevelDecl> decls = sig.TopLevels.Values.ToList();
+ List<MemberDecl> members = sig.StaticMembers.Values.ToList();
+ PrintTopLevelDecls(decls, indent + IndentAmount, fileBeingPrinted);
+ PrintMembers(members, indent + IndentAmount, fileBeingPrinted);
+ Indent(indent); wr.WriteLine("}");
+ }
+ }
+
+ void PrintModuleDefinition(ModuleDefinition module, int indent, string fileBeingPrinted) {
+ Contract.Requires(module != null);
+ Contract.Requires(0 <= indent);
+ if (module.IsAbstract) {
+ wr.Write("abstract ");
+ }
+ wr.Write("module");
+ PrintAttributes(module.Attributes);
+ wr.Write(" {0} ", module.Name);
+ if (module.RefinementBaseName != null) {
+ wr.Write("refines {0} ", Util.Comma(".", module.RefinementBaseName, id => id.val));
+ }
+ if (module.TopLevelDecls.Count == 0) {
+ wr.WriteLine("{ }");
+ } else {
+ wr.WriteLine("{");
+ PrintCallGraph(module, indent + IndentAmount);
+ PrintTopLevelDeclsOrExportedView(module, indent, fileBeingPrinted);
+ Indent(indent);
+ wr.WriteLine("}");
+ }
}
- public void PrintMethod(Method method, int indent, bool printSignatureOnly) {
- Contract.Requires(method != null);
-
- if (PrintModeSkipFunctionOrMethod(method.IsGhost, method.Attributes, method.Name)) { return; }
- Indent(indent);
- string k = method is Constructor ? "constructor" :
- method is InductiveLemma ? "inductive lemma" :
- method is CoLemma ? "colemma" :
- method is Lemma ? "lemma" :
- "method";
- if (method.HasStaticKeyword) { k = "static " + k; }
- if (method.IsGhost && !(method is Lemma) && !(method is FixpointLemma)) { k = "ghost " + k; }
- string nm = method is Constructor && !((Constructor)method).HasName ? "" : method.Name;
- PrintClassMethodHelper(k, method.Attributes, nm, method.TypeArgs);
- if (method.SignatureIsOmitted) {
- wr.WriteLine(" ...");
- } else {
- PrintFormals(method.Ins, method.Name);
- if (method.Outs.Count != 0) {
- if (method.Ins.Count + method.Outs.Count <= 3) {
- wr.Write(" returns ");
- } else {
- wr.WriteLine();
- Indent(indent + 2 * IndentAmount);
- wr.Write("returns ");
+ void PrintTopLevelDeclsOrExportedView(ModuleDefinition module, int indent, string fileBeingPrinted) {
+ bool printViewsOnly = false;
+ List<TopLevelDecl> decls = new List<TopLevelDecl>();
+ // only filter based on view name after resolver.
+ if (afterResolver) {
+ foreach (var nameOfView in DafnyOptions.O.DafnyPrintExportedViews) {
+ foreach (var decl in module.TopLevelDecls) {
+ if (decl.FullName.Equals(nameOfView)) {
+ printViewsOnly = true;
+ decls.Add(decl);
+ }
}
- PrintFormals(method.Outs);
- }
- wr.WriteLine();
- }
-
- int ind = indent + IndentAmount;
- PrintSpec("requires", method.Req, ind);
- if (method.Mod.Expressions != null)
- {
- PrintFrameSpecLine("modifies", method.Mod.Expressions, ind, method.Mod.HasAttributes() ? method.Mod.Attributes : null);
- }
- PrintSpec("ensures", method.Ens, ind);
- PrintDecreasesSpec(method.Decreases, ind);
-
- if (method.Body != null && !printSignatureOnly) {
- Indent(indent);
- PrintStatement(method.Body, indent);
- wr.WriteLine();
- }
- }
-
- internal void PrintFormals(List<Formal> ff, string name = null) {
- Contract.Requires(ff != null);
- if (name != null && name.EndsWith("#")) {
- wr.Write("[");
- PrintFormal(ff[0]);
- wr.Write("]");
- ff = new List<Formal>(ff.Skip(1));
- }
- wr.Write("(");
- string sep = "";
- foreach (Formal f in ff) {
- Contract.Assert(f != null);
- wr.Write(sep);
- sep = ", ";
- PrintFormal(f);
- }
- wr.Write(")");
- }
-
- void PrintFormal(Formal f) {
- Contract.Requires(f != null);
- if (f.IsGhost) {
- wr.Write("ghost ");
- }
- if (f.HasName) {
- wr.Write("{0}: ", f.DisplayName);
- }
- PrintType(f.Type);
- }
-
- internal void PrintSpec(string kind, List<Expression> ee, int indent) {
- Contract.Requires(kind != null);
- Contract.Requires(ee != null);
- foreach (Expression e in ee) {
- Contract.Assert(e != null);
- Indent(indent);
- wr.Write("{0} ", kind);
- PrintExpression(e, true);
- wr.WriteLine();
- }
- }
-
- internal void PrintDecreasesSpec(Specification<Expression> decs, int indent, bool newLine = true) {
- Contract.Requires(decs != null);
- if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
- if (decs.Expressions != null && decs.Expressions.Count != 0) {
- Indent(indent);
- wr.Write("decreases");
- if (decs.HasAttributes())
- {
- PrintAttributes(decs.Attributes);
- }
- wr.Write(" ");
- PrintExpressionList(decs.Expressions, true);
- if (newLine) {
- wr.WriteLine();
- } else {
- wr.Write(" ");
- }
- }
- }
-
- internal void PrintFrameSpecLine(string kind, List<FrameExpression/*!*/> ee, int indent, Attributes attrs, bool newLine = true) {
- Contract.Requires(kind != null);
- Contract.Requires(cce.NonNullElements(ee));
- if (ee != null && ee.Count != 0) {
- Indent(indent);
- wr.Write("{0}", kind);
- if (attrs != null) {
- PrintAttributes(attrs);
- }
- wr.Write(" ");
- PrintFrameExpressionList(ee);
- if (newLine) {
- wr.WriteLine();
- } else {
- wr.Write(" ");
- }
- }
- }
-
- internal void PrintSpec(string kind, List<MaybeFreeExpression> ee, int indent, bool newLine = true) {
- Contract.Requires(kind != null);
- Contract.Requires(ee != null);
- if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
- foreach (MaybeFreeExpression e in ee)
- {
- Contract.Assert(e != null);
- Indent(indent);
- wr.Write("{0}{1}", e.IsFree ? "free " : "", kind);
-
- if (e.HasAttributes())
- {
- PrintAttributes(e.Attributes);
- }
-
- wr.Write(" ");
- PrintExpression(e.E, true);
- if (newLine) {
- wr.WriteLine();
- } else {
- wr.Write(" ");
- }
- }
- }
-
- // ----------------------------- PrintType -----------------------------
-
- public void PrintType(Type ty) {
- Contract.Requires(ty != null);
- wr.Write(ty.ToString());
- }
-
- public void PrintType(string prefix, Type ty) {
- Contract.Requires(prefix != null);
- Contract.Requires(ty != null);
- string s = ty.ToString();
- if (s != "?") {
- wr.Write("{0}{1}", prefix, s);
- }
- }
-
- string EqualitySupportSuffix(TypeParameter.EqualitySupportValue es) {
- if (es == TypeParameter.EqualitySupportValue.Required ||
- (es == TypeParameter.EqualitySupportValue.InferredRequired && DafnyOptions.O.DafnyPrintResolvedFile != null)) {
- return "(==)";
- } else {
- return "";
- }
- }
-
- // ----------------------------- PrintStatement -----------------------------
-
- /// <summary>
- /// Prints from the current position of the current line.
- /// If the statement requires several lines, subsequent lines are indented at "indent".
- /// No newline is printed after the statement.
- /// </summary>
- public void PrintStatement(Statement stmt, int indent) {
- Contract.Requires(stmt != null);
-
- if (stmt.IsGhost && printMode == DafnyOptions.PrintModes.NoGhost) { return; }
- for (LList<Label> label = stmt.Labels; label != null; label = label.Next) {
- if (label.Data.Name != null) {
- wr.WriteLine("label {0}:", label.Data.Name);
- Indent(indent);
}
}
-
- if (stmt is PredicateStmt) {
- if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
- Expression expr = ((PredicateStmt)stmt).Expr;
- wr.Write(stmt is AssertStmt ? "assert" : "assume");
- if (stmt.Attributes != null) {
- PrintAttributes(stmt.Attributes);
- }
- wr.Write(" ");
- PrintExpression(expr, true);
- wr.Write(";");
-
- } else if (stmt is PrintStmt) {
- PrintStmt s = (PrintStmt)stmt;
- wr.Write("print");
- PrintAttributeArgs(s.Args, true);
- wr.Write(";");
-
- } else if (stmt is BreakStmt) {
- BreakStmt s = (BreakStmt)stmt;
- if (s.TargetLabel != null) {
- wr.Write("break {0};", s.TargetLabel);
- } else {
- string sep = "";
- for (int i = 0; i < s.BreakCount; i++) {
- wr.Write("{0}break", sep);
- sep = " ";
- }
- wr.Write(";");
- }
-
- } else if (stmt is ProduceStmt) {
- var s = (ProduceStmt) stmt;
- wr.Write(s is YieldStmt ? "yield" : "return");
- if (s.rhss != null) {
- var sep = " ";
- foreach (var rhs in s.rhss) {
- wr.Write(sep);
- PrintRhs(rhs);
- sep = ", ";
- }
- }
- wr.Write(";");
-
- } else if (stmt is AssignStmt) {
- AssignStmt s = (AssignStmt)stmt;
- PrintExpression(s.Lhs, true);
- wr.Write(" := ");
- PrintRhs(s.Rhs);
- wr.Write(";");
-
- } else if (stmt is BlockStmt) {
- wr.WriteLine("{");
- int ind = indent + IndentAmount;
- foreach (Statement s in ((BlockStmt)stmt).Body) {
- Indent(ind);
- PrintStatement(s, ind);
- wr.WriteLine();
- }
- Indent(indent);
- wr.Write("}");
-
- } else if (stmt is IfStmt) {
- IfStmt s = (IfStmt)stmt;
- PrintIfStatement(indent, s, false);
-
- } else if (stmt is AlternativeStmt) {
- var s = (AlternativeStmt)stmt;
- wr.WriteLine("if {");
- PrintAlternatives(indent, s.Alternatives);
- Indent(indent);
- wr.Write("}");
-
- } else if (stmt is WhileStmt) {
- WhileStmt s = (WhileStmt)stmt;
- PrintWhileStatement(indent, s, false, false);
-
- } else if (stmt is AlternativeLoopStmt) {
- var s = (AlternativeLoopStmt)stmt;
- wr.WriteLine("while");
- PrintSpec("invariant", s.Invariants, indent + IndentAmount);
- PrintDecreasesSpec(s.Decreases, indent + IndentAmount);
-
- Indent(indent);
- wr.WriteLine("{");
- PrintAlternatives(indent, s.Alternatives);
- Indent(indent);
- wr.Write("}");
-
- } else if (stmt is ForallStmt) {
+ PrintTopLevelDecls(printViewsOnly ? decls : module.TopLevelDecls, indent + IndentAmount, fileBeingPrinted);
+ }
+
+ void PrintIteratorSignature(IteratorDecl iter, int indent) {
+ Indent(indent);
+ PrintClassMethodHelper("iterator", iter.Attributes, iter.Name, iter.TypeArgs);
+ if (iter.SignatureIsOmitted) {
+ wr.WriteLine(" ...");
+ } else {
+ PrintFormals(iter.Ins);
+ if (iter.Outs.Count != 0) {
+ if (iter.Ins.Count + iter.Outs.Count <= 3) {
+ wr.Write(" yields ");
+ } else {
+ wr.WriteLine();
+ Indent(indent + 2 * IndentAmount);
+ wr.Write("yields ");
+ }
+ PrintFormals(iter.Outs);
+ }
+ wr.WriteLine();
+ }
+
+ int ind = indent + IndentAmount;
+ PrintSpec("requires", iter.Requires, ind);
+ if (iter.Reads.Expressions != null) {
+ PrintFrameSpecLine("reads", iter.Reads.Expressions, ind, iter.Reads.HasAttributes() ? iter.Reads.Attributes : null);
+ }
+ if (iter.Modifies.Expressions != null) {
+ PrintFrameSpecLine("modifies", iter.Modifies.Expressions, ind, iter.Modifies.HasAttributes() ? iter.Modifies.Attributes : null);
+ }
+ PrintSpec("yield requires", iter.YieldRequires, ind);
+ PrintSpec("yield ensures", iter.YieldEnsures, ind);
+ PrintSpec("ensures", iter.Ensures, ind);
+ PrintDecreasesSpec(iter.Decreases, ind);
+ }
+
+ private void PrintIteratorClass(IteratorDecl iter, int indent, string fileBeingPrinted) {
+ PrintClassMethodHelper("class", null, iter.Name, iter.TypeArgs);
+ wr.WriteLine(" {");
+ PrintMembers(iter.Members, indent + IndentAmount, fileBeingPrinted);
+ Indent(indent); wr.WriteLine("}");
+ }
+
+ public void PrintClass(ClassDecl c, int indent, string fileBeingPrinted) {
+ Contract.Requires(c != null);
+ Indent(indent);
+ PrintClassMethodHelper((c is TraitDecl) ? "trait" : "class", c.Attributes, c.Name, c.TypeArgs);
+ string sep = " extends ";
+ foreach (var trait in c.TraitsTyp) {
+ wr.Write(sep);
+ PrintType(trait);
+ sep = ", ";
+ }
+ if (c.Members.Count == 0) {
+ wr.WriteLine(" { }");
+ } else {
+ wr.WriteLine(" {");
+ PrintMembers(c.Members, indent + IndentAmount, fileBeingPrinted);
+ Indent(indent);
+ wr.WriteLine("}");
+ }
+ }
+
+ public void PrintMembers(List<MemberDecl> members, int indent, string fileBeingPrinted)
+ {
+ Contract.Requires(members != null);
+
+ int state = 0; // 0 - no members yet; 1 - previous member was a field; 2 - previous member was non-field
+ foreach (MemberDecl m in members) {
+ if (PrintModeSkipGeneral(m.tok, fileBeingPrinted)) { continue; }
+ if (m is Method) {
+ if (state != 0) { wr.WriteLine(); }
+ PrintMethod((Method)m, indent, false);
+ var com = m as FixpointLemma;
+ if (com != null && com.PrefixLemma != null) {
+ Indent(indent); wr.WriteLine("/***");
+ PrintMethod(com.PrefixLemma, indent, false);
+ Indent(indent); wr.WriteLine("***/");
+ }
+ state = 2;
+ } else if (m is Field) {
+ if (state == 2) { wr.WriteLine(); }
+ PrintField((Field)m, indent);
+ state = 1;
+ } else if (m is Function) {
+ if (state != 0) { wr.WriteLine(); }
+ PrintFunction((Function)m, indent, false);
+ var fixp = m as FixpointPredicate;
+ if (fixp != null && fixp.PrefixPredicate != null) {
+ Indent(indent); wr.WriteLine("/***");
+ PrintFunction(fixp.PrefixPredicate, indent, false);
+ Indent(indent); wr.WriteLine("***/");
+ }
+ state = 2;
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member
+ }
+ }
+ }
+
+ /// <summary>
+ /// Prints no space before "kind", but does print a space before "attrs" and "name".
+ /// </summary>
+ void PrintClassMethodHelper(string kind, Attributes attrs, string name, List<TypeParameter> typeArgs) {
+ Contract.Requires(kind != null);
+ Contract.Requires(name != null);
+ Contract.Requires(typeArgs != null);
+ if (kind.Length != 0) {
+ wr.Write(kind);
+ }
+
+ PrintAttributes(attrs);
+
+ wr.Write(" {0}", name);
+ PrintTypeParams(typeArgs);
+ }
+
+ private void PrintTypeParams(List<TypeParameter> typeArgs) {
+ Contract.Requires(typeArgs != null);
+ if (typeArgs.Count != 0) {
+ wr.Write("<" +
+ Util.Comma(", ", typeArgs,
+ tp => tp.Name + EqualitySupportSuffix(tp.EqualitySupport))
+ + ">");
+ }
+ }
+
+ private void PrintTypeInstantiation(List<Type> typeArgs) {
+ Contract.Requires(typeArgs == null || typeArgs.Count != 0);
+ if (typeArgs != null) {
+ wr.Write("<{0}>", Util.Comma(",", typeArgs, ty => ty.ToString()));
+ }
+ }
+
+ public void PrintDatatype(DatatypeDecl dt, int indent) {
+ Contract.Requires(dt != null);
+ Indent(indent);
+ PrintClassMethodHelper(dt is IndDatatypeDecl ? "datatype" : "codatatype", dt.Attributes, dt.Name, dt.TypeArgs);
+ wr.Write(" =");
+ string sep = "";
+ foreach (DatatypeCtor ctor in dt.Ctors) {
+ wr.Write(sep);
+ PrintClassMethodHelper("", ctor.Attributes, ctor.Name, new List<TypeParameter>());
+ if (ctor.Formals.Count != 0) {
+ PrintFormals(ctor.Formals);
+ }
+ sep = " |";
+ }
+ wr.WriteLine();
+ }
+
+ /// <summary>
+ /// Prints a space before each attribute.
+ /// </summary>
+ public void PrintAttributes(Attributes a) {
+ if (a != null) {
+ PrintAttributes(a.Prev);
+ wr.Write(" ");
+ PrintOneAttribute(a);
+ }
+ }
+ public void PrintOneAttribute(Attributes a, string nameSubstitution = null) {
+ Contract.Requires(a != null);
+ var name = nameSubstitution ?? a.Name;
+ var usAttribute = name.StartsWith("_");
+ wr.Write("{1}{{:{0}", name, usAttribute ? "/*" : "");
+ if (a.Args != null) {
+ PrintAttributeArgs(a.Args, false);
+ }
+ wr.Write("}}{0}", usAttribute ? "*/" : "");
+ }
+
+ public void PrintAttributeArgs(List<Expression> args, bool isFollowedBySemicolon) {
+ Contract.Requires(args != null);
+ string prefix = " ";
+ foreach (var arg in args) {
+ Contract.Assert(arg != null);
+ wr.Write(prefix);
+ prefix = ", ";
+ PrintExpression(arg, isFollowedBySemicolon);
+ }
+ }
+
+ public void PrintField(Field field, int indent) {
+ Contract.Requires(field != null);
+ Indent(indent);
+ if (field.IsGhost) {
+ wr.Write("ghost ");
+ }
+ wr.Write("var");
+ PrintAttributes(field.Attributes);
+ wr.Write(" {0}: ", field.Name);
+ PrintType(field.Type);
+ if (field.IsUserMutable) {
+ // nothing more to say
+ } else if (field.IsMutable) {
+ wr.Write(" // non-assignable");
+ } else {
+ wr.Write(" // immutable");
+ }
+ wr.WriteLine();
+ }
+
+ public void PrintFunction(Function f, int indent, bool printSignatureOnly) {
+ Contract.Requires(f != null);
+
+ if (PrintModeSkipFunctionOrMethod(f.IsGhost, f.Attributes, f.Name)) { return; }
+ var isPredicate = f is Predicate || f is PrefixPredicate;
+ Indent(indent);
+ string k = isPredicate ? "predicate" : f is InductivePredicate ? "inductive predicate" : f is CoPredicate ? "copredicate" : "function";
+ if (f.IsProtected) { k = "protected " + k; }
+ if (f.HasStaticKeyword) { k = "static " + k; }
+ if (!f.IsGhost) { k += " method"; }
+ PrintClassMethodHelper(k, f.Attributes, f.Name, f.TypeArgs);
+ if (f.SignatureIsOmitted) {
+ wr.WriteLine(" ...");
+ } else {
+ PrintFormals(f.Formals, f.Name);
+ if (!isPredicate) {
+ wr.Write(": ");
+ PrintType(f.ResultType);
+ }
+ wr.WriteLine();
+ }
+
+ int ind = indent + IndentAmount;
+ PrintSpec("requires", f.Req, ind);
+ PrintFrameSpecLine("reads", f.Reads, ind, null);
+ PrintSpec("ensures", f.Ens, ind);
+ PrintDecreasesSpec(f.Decreases, ind);
+ if (f.Body != null && !printSignatureOnly) {
+ Indent(indent);
+ wr.WriteLine("{");
+ PrintExtendedExpr(f.Body, ind, true, false);
+ Indent(indent);
+ wr.WriteLine("}");
+ }
+ }
+
+ // ----------------------------- PrintMethod -----------------------------
+
+ const int IndentAmount = 2; // The amount of indent for each new scope
+ const string BunchaSpaces = " ";
+ void Indent(int amount)
+ {
+ Contract.Requires(0 <= amount);
+
+ while (0 < amount) {
+ wr.Write(BunchaSpaces.Substring(0, amount));
+ amount -= BunchaSpaces.Length;
+ }
+ }
+
+ private bool PrintModeSkipFunctionOrMethod(bool IsGhost, Attributes attributes, string name)
+ {
+ if (printMode == DafnyOptions.PrintModes.NoGhost && IsGhost)
+ { return true; }
+ if (printMode == DafnyOptions.PrintModes.NoIncludes || printMode == DafnyOptions.PrintModes.NoGhost)
+ {
+ bool verify = true;
+ if (Attributes.ContainsBool(attributes, "verify", ref verify) && !verify)
+ { return true; }
+ if (name.Contains("INTERNAL") || name.StartsWith("reveal_"))
+ { return true; }
+ }
+ return false;
+ }
+
+ private bool PrintModeSkipGeneral(Bpl.IToken tok, string fileBeingPrinted)
+ {
+ return (printMode == DafnyOptions.PrintModes.NoIncludes || printMode == DafnyOptions.PrintModes.NoGhost)
+ && (tok.filename != null && fileBeingPrinted != null && Path.GetFullPath(tok.filename) != fileBeingPrinted);
+ }
+
+ public void PrintMethod(Method method, int indent, bool printSignatureOnly) {
+ Contract.Requires(method != null);
+
+ if (PrintModeSkipFunctionOrMethod(method.IsGhost, method.Attributes, method.Name)) { return; }
+ Indent(indent);
+ string k = method is Constructor ? "constructor" :
+ method is InductiveLemma ? "inductive lemma" :
+ method is CoLemma ? "colemma" :
+ method is Lemma ? "lemma" :
+ "method";
+ if (method.HasStaticKeyword) { k = "static " + k; }
+ if (method.IsGhost && !(method is Lemma) && !(method is FixpointLemma)) { k = "ghost " + k; }
+ string nm = method is Constructor && !((Constructor)method).HasName ? "" : method.Name;
+ PrintClassMethodHelper(k, method.Attributes, nm, method.TypeArgs);
+ if (method.SignatureIsOmitted) {
+ wr.WriteLine(" ...");
+ } else {
+ PrintFormals(method.Ins, method.Name);
+ if (method.Outs.Count != 0) {
+ if (method.Ins.Count + method.Outs.Count <= 3) {
+ wr.Write(" returns ");
+ } else {
+ wr.WriteLine();
+ Indent(indent + 2 * IndentAmount);
+ wr.Write("returns ");
+ }
+ PrintFormals(method.Outs);
+ }
+ wr.WriteLine();
+ }
+
+ int ind = indent + IndentAmount;
+ PrintSpec("requires", method.Req, ind);
+ if (method.Mod.Expressions != null)
+ {
+ PrintFrameSpecLine("modifies", method.Mod.Expressions, ind, method.Mod.HasAttributes() ? method.Mod.Attributes : null);
+ }
+ PrintSpec("ensures", method.Ens, ind);
+ PrintDecreasesSpec(method.Decreases, ind);
+
+ if (method.Body != null && !printSignatureOnly) {
+ Indent(indent);
+ PrintStatement(method.Body, indent);
+ wr.WriteLine();
+ }
+ }
+
+ internal void PrintFormals(List<Formal> ff, string name = null) {
+ Contract.Requires(ff != null);
+ if (name != null && name.EndsWith("#")) {
+ wr.Write("[");
+ PrintFormal(ff[0]);
+ wr.Write("]");
+ ff = new List<Formal>(ff.Skip(1));
+ }
+ wr.Write("(");
+ string sep = "";
+ foreach (Formal f in ff) {
+ Contract.Assert(f != null);
+ wr.Write(sep);
+ sep = ", ";
+ PrintFormal(f);
+ }
+ wr.Write(")");
+ }
+
+ void PrintFormal(Formal f) {
+ Contract.Requires(f != null);
+ if (f.IsGhost) {
+ wr.Write("ghost ");
+ }
+ if (f.HasName) {
+ wr.Write("{0}: ", f.DisplayName);
+ }
+ PrintType(f.Type);
+ }
+
+ internal void PrintSpec(string kind, List<Expression> ee, int indent) {
+ Contract.Requires(kind != null);
+ Contract.Requires(ee != null);
+ foreach (Expression e in ee) {
+ Contract.Assert(e != null);
+ Indent(indent);
+ wr.Write("{0} ", kind);
+ PrintExpression(e, true);
+ wr.WriteLine();
+ }
+ }
+
+ internal void PrintDecreasesSpec(Specification<Expression> decs, int indent, bool newLine = true) {
+ Contract.Requires(decs != null);
+ if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
+ if (decs.Expressions != null && decs.Expressions.Count != 0) {
+ Indent(indent);
+ wr.Write("decreases");
+ if (decs.HasAttributes())
+ {
+ PrintAttributes(decs.Attributes);
+ }
+ wr.Write(" ");
+ PrintExpressionList(decs.Expressions, true);
+ if (newLine) {
+ wr.WriteLine();
+ } else {
+ wr.Write(" ");
+ }
+ }
+ }
+
+ internal void PrintFrameSpecLine(string kind, List<FrameExpression/*!*/> ee, int indent, Attributes attrs, bool newLine = true) {
+ Contract.Requires(kind != null);
+ Contract.Requires(cce.NonNullElements(ee));
+ if (ee != null && ee.Count != 0) {
+ Indent(indent);
+ wr.Write("{0}", kind);
+ if (attrs != null) {
+ PrintAttributes(attrs);
+ }
+ wr.Write(" ");
+ PrintFrameExpressionList(ee);
+ if (newLine) {
+ wr.WriteLine();
+ } else {
+ wr.Write(" ");
+ }
+ }
+ }
+
+ internal void PrintSpec(string kind, List<MaybeFreeExpression> ee, int indent, bool newLine = true) {
+ Contract.Requires(kind != null);
+ Contract.Requires(ee != null);
+ if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
+ foreach (MaybeFreeExpression e in ee)
+ {
+ Contract.Assert(e != null);
+ Indent(indent);
+ wr.Write("{0}{1}", e.IsFree ? "free " : "", kind);
+
+ if (e.HasAttributes())
+ {
+ PrintAttributes(e.Attributes);
+ }
+
+ wr.Write(" ");
+ PrintExpression(e.E, true);
+ if (newLine) {
+ wr.WriteLine();
+ } else {
+ wr.Write(" ");
+ }
+ }
+ }
+
+ // ----------------------------- PrintType -----------------------------
+
+ public void PrintType(Type ty) {
+ Contract.Requires(ty != null);
+ wr.Write(ty.ToString());
+ }
+
+ public void PrintType(string prefix, Type ty) {
+ Contract.Requires(prefix != null);
+ Contract.Requires(ty != null);
+ string s = ty.ToString();
+ if (s != "?") {
+ wr.Write("{0}{1}", prefix, s);
+ }
+ }
+
+ string EqualitySupportSuffix(TypeParameter.EqualitySupportValue es) {
+ if (es == TypeParameter.EqualitySupportValue.Required ||
+ (es == TypeParameter.EqualitySupportValue.InferredRequired && DafnyOptions.O.DafnyPrintResolvedFile != null)) {
+ return "(==)";
+ } else {
+ return "";
+ }
+ }
+
+ // ----------------------------- PrintStatement -----------------------------
+
+ /// <summary>
+ /// Prints from the current position of the current line.
+ /// If the statement requires several lines, subsequent lines are indented at "indent".
+ /// No newline is printed after the statement.
+ /// </summary>
+ public void PrintStatement(Statement stmt, int indent) {
+ Contract.Requires(stmt != null);
+
+ if (stmt.IsGhost && printMode == DafnyOptions.PrintModes.NoGhost) { return; }
+ for (LList<Label> label = stmt.Labels; label != null; label = label.Next) {
+ if (label.Data.Name != null) {
+ wr.WriteLine("label {0}:", label.Data.Name);
+ Indent(indent);
+ }
+ }
+
+ if (stmt is PredicateStmt) {
+ if (printMode == DafnyOptions.PrintModes.NoGhost) { return; }
+ Expression expr = ((PredicateStmt)stmt).Expr;
+ wr.Write(stmt is AssertStmt ? "assert" : "assume");
+ if (stmt.Attributes != null) {
+ PrintAttributes(stmt.Attributes);
+ }
+ wr.Write(" ");
+ PrintExpression(expr, true);
+ wr.Write(";");
+
+ } else if (stmt is PrintStmt) {
+ PrintStmt s = (PrintStmt)stmt;
+ wr.Write("print");
+ PrintAttributeArgs(s.Args, true);
+ wr.Write(";");
+
+ } else if (stmt is BreakStmt) {
+ BreakStmt s = (BreakStmt)stmt;
+ if (s.TargetLabel != null) {
+ wr.Write("break {0};", s.TargetLabel);
+ } else {
+ string sep = "";
+ for (int i = 0; i < s.BreakCount; i++) {
+ wr.Write("{0}break", sep);
+ sep = " ";
+ }
+ wr.Write(";");
+ }
+
+ } else if (stmt is ProduceStmt) {
+ var s = (ProduceStmt) stmt;
+ wr.Write(s is YieldStmt ? "yield" : "return");
+ if (s.rhss != null) {
+ var sep = " ";
+ foreach (var rhs in s.rhss) {
+ wr.Write(sep);
+ PrintRhs(rhs);
+ sep = ", ";
+ }
+ }
+ wr.Write(";");
+
+ } else if (stmt is AssignStmt) {
+ AssignStmt s = (AssignStmt)stmt;
+ PrintExpression(s.Lhs, true);
+ wr.Write(" := ");
+ PrintRhs(s.Rhs);
+ wr.Write(";");
+
+ } else if (stmt is BlockStmt) {
+ wr.WriteLine("{");
+ int ind = indent + IndentAmount;
+ foreach (Statement s in ((BlockStmt)stmt).Body) {
+ Indent(ind);
+ PrintStatement(s, ind);
+ wr.WriteLine();
+ }
+ Indent(indent);
+ wr.Write("}");
+
+ } else if (stmt is IfStmt) {
+ IfStmt s = (IfStmt)stmt;
+ PrintIfStatement(indent, s, false);
+
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ wr.WriteLine("if {");
+ PrintAlternatives(indent, s.Alternatives);
+ Indent(indent);
+ wr.Write("}");
+
+ } else if (stmt is WhileStmt) {
+ WhileStmt s = (WhileStmt)stmt;
+ PrintWhileStatement(indent, s, false, false);
+
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ wr.WriteLine("while");
+ PrintSpec("invariant", s.Invariants, indent + IndentAmount);
+ PrintDecreasesSpec(s.Decreases, indent + IndentAmount);
+
+ Indent(indent);
+ wr.WriteLine("{");
+ PrintAlternatives(indent, s.Alternatives);
+ Indent(indent);
+ wr.Write("}");
+
+ } else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
- wr.Write("forall");
- if (s.BoundVars.Count != 0) {
- wr.Write(" ");
- PrintQuantifierDomain(s.BoundVars, s.Attributes, s.Range);
- }
- if (s.Ens.Count == 0) {
- wr.Write(" ");
- } else {
- wr.WriteLine();
- PrintSpec("ensures", s.Ens, indent + IndentAmount, s.Body != null);
- Indent(indent);
- }
- if (s.Body != null) {
- PrintStatement(s.Body, indent);
- }
-
- } else if (stmt is ModifyStmt) {
- var s = (ModifyStmt)stmt;
- PrintModifyStmt(indent, s, false);
-
- } else if (stmt is CalcStmt) {
- CalcStmt s = (CalcStmt)stmt;
- if (printMode == DafnyOptions.PrintModes.NoGhost) { return; } // Calcs don't get a "ghost" attribute, but they are.
- wr.Write("calc ");
- if (!s.Op.Equals(CalcStmt.DefaultOp)) {
- PrintCalcOp(s.Op);
- wr.Write(" ");
- }
- wr.WriteLine("{");
- int lineInd = indent + IndentAmount;
- int lineCount = s.Lines.Count == 0 ? 0 : s.Lines.Count - 1; // if nonempty, .Lines always contains a duplicated last line
- // The number of op/hints is commonly one less than the number of lines, but
- // it can also equal the number of lines for empty calc's and for calc's with
- // a dangling hint.
- int hintCount = s.Lines.Count != 0 && s.Hints.Last().Body.Count == 0 ? lineCount - 1 : lineCount;
- for (var i = 0; i < lineCount; i++) {
- var e = s.Lines[i];
- var op = s.StepOps[i];
- var h = s.Hints[i];
- // print the line
- Indent(lineInd);
- PrintExpression(e, true, lineInd);
- wr.WriteLine(";");
- if (i == hintCount) {
- break;
+ if (s.ForallExpressions != null) {
+ foreach (var expr in s.ForallExpressions) {
+ PrintExpression(expr, false, " ensures ");
}
- // print the operator, if any
- if (!s.Op.Equals(op)) {
- Indent(indent); // this lines up with the "calc"
- PrintCalcOp(op);
- wr.WriteLine();
- }
- // print the hints
- foreach (var st in h.Body) {
- Indent(lineInd);
- PrintStatement(st, lineInd);
- wr.WriteLine();
- }
- }
- Indent(indent);
- wr.Write("}");
-
- } else if (stmt is MatchStmt) {
- MatchStmt s = (MatchStmt)stmt;
- wr.Write("match ");
- PrintExpression(s.Source, false);
- if (s.UsesOptionalBraces) {
- wr.Write(" {");
- }
- int caseInd = indent + (s.UsesOptionalBraces ? IndentAmount : 0);
- foreach (MatchCaseStmt mc in s.Cases) {
- wr.WriteLine();
- Indent(caseInd);
- wr.Write("case {0}", mc.Id);
- if (mc.Arguments.Count != 0) {
- string sep = "(";
- foreach (BoundVar bv in mc.Arguments) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- if (bv.Type is NonProxyType) {
- wr.Write(": {0}", bv.Type);
- }
- sep = ", ";
- }
- wr.Write(")");
+ } else {
+ wr.Write("forall");
+ if (s.BoundVars.Count != 0) {
+ wr.Write(" ");
+ PrintQuantifierDomain(s.BoundVars, s.Attributes, s.Range);
}
- wr.Write(" =>");
- foreach (Statement bs in mc.Body) {
+ if (s.Ens.Count == 0) {
+ wr.Write(" ");
+ } else {
wr.WriteLine();
- Indent(caseInd + IndentAmount);
- PrintStatement(bs, caseInd + IndentAmount);
+ PrintSpec("ensures", s.Ens, indent + IndentAmount, s.Body != null);
+ Indent(indent);
}
- }
- if (s.UsesOptionalBraces) {
- wr.WriteLine();
- Indent(indent);
- wr.Write("}");
- }
-
- } else if (stmt is ConcreteUpdateStatement) {
- var s = (ConcreteUpdateStatement)stmt;
- string sep = "";
- foreach (var lhs in s.Lhss) {
- wr.Write(sep);
- PrintExpression(lhs, true);
- sep = ", ";
- }
- PrintUpdateRHS(s);
- wr.Write(";");
-
- } else if (stmt is VarDeclStmt) {
- var s = (VarDeclStmt)stmt;
- if (s.Locals.Exists(v => v.IsGhost) && printMode == DafnyOptions.PrintModes.NoGhost) { return; }
- if (s.Locals.Exists(v => v.IsGhost)) {
- wr.Write("ghost ");
- }
+ }
+ if (s.Body != null) {
+ PrintStatement(s.Body, indent);
+ }
+
+ } else if (stmt is ModifyStmt) {
+ var s = (ModifyStmt)stmt;
+ PrintModifyStmt(indent, s, false);
+
+ } else if (stmt is CalcStmt) {
+ CalcStmt s = (CalcStmt)stmt;
+ if (printMode == DafnyOptions.PrintModes.NoGhost) { return; } // Calcs don't get a "ghost" attribute, but they are.
+ wr.Write("calc ");
+ if (!s.Op.Equals(CalcStmt.DefaultOp)) {
+ PrintCalcOp(s.Op);
+ wr.Write(" ");
+ }
+ wr.WriteLine("{");
+ int lineInd = indent + IndentAmount;
+ int lineCount = s.Lines.Count == 0 ? 0 : s.Lines.Count - 1; // if nonempty, .Lines always contains a duplicated last line
+ // The number of op/hints is commonly one less than the number of lines, but
+ // it can also equal the number of lines for empty calc's and for calc's with
+ // a dangling hint.
+ int hintCount = s.Lines.Count != 0 && s.Hints.Last().Body.Count == 0 ? lineCount - 1 : lineCount;
+ for (var i = 0; i < lineCount; i++) {
+ var e = s.Lines[i];
+ var op = s.StepOps[i];
+ var h = s.Hints[i];
+ // print the line
+ Indent(lineInd);
+ PrintExpression(e, true, lineInd);
+ wr.WriteLine(";");
+ if (i == hintCount) {
+ break;
+ }
+ // print the operator, if any
+ if (!s.Op.Equals(op)) {
+ Indent(indent); // this lines up with the "calc"
+ PrintCalcOp(op);
+ wr.WriteLine();
+ }
+ // print the hints
+ foreach (var st in h.Body) {
+ Indent(lineInd);
+ PrintStatement(st, lineInd);
+ wr.WriteLine();
+ }
+ }
+ Indent(indent);
+ wr.Write("}");
+
+ } else if (stmt is MatchStmt) {
+ MatchStmt s = (MatchStmt)stmt;
+ wr.Write("match ");
+ PrintExpression(s.Source, false);
+ if (s.UsesOptionalBraces) {
+ wr.Write(" {");
+ }
+ int caseInd = indent + (s.UsesOptionalBraces ? IndentAmount : 0);
+ foreach (MatchCaseStmt mc in s.Cases) {
+ wr.WriteLine();
+ Indent(caseInd);
+ wr.Write("case {0}", mc.Id);
+ PrintMatchCaseArgument(mc);
+ wr.Write(" =>");
+ foreach (Statement bs in mc.Body) {
+ wr.WriteLine();
+ Indent(caseInd + IndentAmount);
+ PrintStatement(bs, caseInd + IndentAmount);
+ }
+ }
+ if (s.UsesOptionalBraces) {
+ wr.WriteLine();
+ Indent(indent);
+ wr.Write("}");
+ }
+
+ } else if (stmt is ConcreteUpdateStatement) {
+ var s = (ConcreteUpdateStatement)stmt;
+ string sep = "";
+ foreach (var lhs in s.Lhss) {
+ wr.Write(sep);
+ PrintExpression(lhs, true);
+ sep = ", ";
+ }
+ PrintUpdateRHS(s);
+ wr.Write(";");
+
+ } else if (stmt is VarDeclStmt) {
+ var s = (VarDeclStmt)stmt;
+ if (s.Locals.Exists(v => v.IsGhost) && printMode == DafnyOptions.PrintModes.NoGhost) { return; }
+ if (s.Locals.Exists(v => v.IsGhost)) {
+ wr.Write("ghost ");
+ }
+ wr.Write("var");
+ string sep = "";
+ foreach (var local in s.Locals) {
+ wr.Write(sep);
+ if (local.Attributes != null) {
+ PrintAttributes(local.Attributes);
+ }
+ wr.Write(" {0}", local.DisplayName);
+ PrintType(": ", local.OptionalType);
+ sep = ",";
+ }
+ if (s.Update != null) {
+ PrintUpdateRHS(s.Update);
+ }
+ wr.Write(";");
+
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
wr.Write("var");
string sep = "";
- foreach (var local in s.Locals) {
- wr.Write(sep);
- if (local.Attributes != null) {
- PrintAttributes(local.Attributes);
- }
- wr.Write(" {0}", local.DisplayName);
- PrintType(": ", local.OptionalType);
- sep = ",";
- }
- if (s.Update != null) {
- PrintUpdateRHS(s.Update);
- }
- wr.Write(";");
-
- } else if (stmt is SkeletonStatement) {
- var s = (SkeletonStatement)stmt;
- if (s.S == null) {
- wr.Write("...;");
- } else if (s.S is AssertStmt) {
- Contract.Assert(s.ConditionOmitted);
- wr.Write("assert ...;");
- } else if (s.S is AssumeStmt) {
- Contract.Assert(s.ConditionOmitted);
- wr.Write("assume ...;");
- } else if (s.S is IfStmt) {
- PrintIfStatement(indent, (IfStmt)s.S, s.ConditionOmitted);
- } else if (s.S is WhileStmt) {
- PrintWhileStatement(indent, (WhileStmt)s.S, s.ConditionOmitted, s.BodyOmitted);
- } else if (s.S is ModifyStmt) {
- PrintModifyStmt(indent, (ModifyStmt)s.S, true);
- } else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected skeleton statement
- }
-
- } else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
- }
- }
-
- private void PrintModifyStmt(int indent, ModifyStmt s, bool omitFrame) {
- Contract.Requires(0 <= indent);
- Contract.Requires(s != null);
- Contract.Requires(!omitFrame || s.Mod.Expressions.Count == 0);
-
- wr.Write("modify");
- PrintAttributes(s.Mod.Attributes);
- wr.Write(" ");
- if (omitFrame) {
- wr.Write("...");
- } else {
- PrintFrameExpressionList(s.Mod.Expressions);
- }
- if (s.Body != null) {
- // There's a possible syntactic ambiguity, namely if the frame is empty (more precisely,
- // if s.Mod.Expressions.Count is 0). Since the statement was parsed at some point, this
- // situation can occur only if the modify statement inherited its frame by refinement
- // and we're printing the post-resolve AST. In this special case, print an explicit
- // empty set as the frame.
- if (s.Mod.Expressions.Count == 0) {
- wr.Write(" {}");
- }
- wr.Write(" ");
- PrintStatement(s.Body, indent);
- } else {
- wr.Write(";");
- }
- }
-
- /// <summary>
- /// Does not print LHS
- /// </summary>
- void PrintUpdateRHS(ConcreteUpdateStatement s) {
- Contract.Requires(s != null);
- if (s is UpdateStmt) {
- var update = (UpdateStmt)s;
- if (update.Lhss.Count != 0) {
- wr.Write(" := ");
- }
- var sep = "";
- foreach (var rhs in update.Rhss) {
+ foreach (var lhs in s.LHSs) {
wr.Write(sep);
- PrintRhs(rhs);
+ PrintCasePattern(lhs);
sep = ", ";
}
- } else if (s is AssignSuchThatStmt) {
- var update = (AssignSuchThatStmt)s;
- wr.Write(" :| ");
- if (update.AssumeToken != null) {
- wr.Write("assume ");
- }
- PrintExpression(update.Expr, true);
- } else {
- Contract.Assert(s == null); // otherwise, unknown type
- }
- }
-
- void PrintIfStatement(int indent, IfStmt s, bool omitGuard) {
- while (true) {
- if (omitGuard) {
- wr.Write("if ... ");
- } else {
- wr.Write("if ");
- PrintGuard(s.Guard);
- wr.Write(" ");
- }
- PrintStatement(s.Thn, indent);
- if (s.Els == null) {
- break;
- }
+ wr.Write(" := ");
+ PrintExpressionList(s.RHSs, true);
+ wr.WriteLine(";");
+
+ } else if (stmt is SkeletonStatement) {
+ var s = (SkeletonStatement)stmt;
+ if (s.S == null) {
+ wr.Write("...;");
+ } else if (s.S is AssertStmt) {
+ Contract.Assert(s.ConditionOmitted);
+ wr.Write("assert ...;");
+ } else if (s.S is AssumeStmt) {
+ Contract.Assert(s.ConditionOmitted);
+ wr.Write("assume ...;");
+ } else if (s.S is IfStmt) {
+ PrintIfStatement(indent, (IfStmt)s.S, s.ConditionOmitted);
+ } else if (s.S is WhileStmt) {
+ PrintWhileStatement(indent, (WhileStmt)s.S, s.ConditionOmitted, s.BodyOmitted);
+ } else if (s.S is ModifyStmt) {
+ PrintModifyStmt(indent, (ModifyStmt)s.S, true);
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected skeleton statement
+ }
+
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
+ }
+ }
+
+ private void PrintModifyStmt(int indent, ModifyStmt s, bool omitFrame) {
+ Contract.Requires(0 <= indent);
+ Contract.Requires(s != null);
+ Contract.Requires(!omitFrame || s.Mod.Expressions.Count == 0);
+
+ wr.Write("modify");
+ PrintAttributes(s.Mod.Attributes);
+ wr.Write(" ");
+ if (omitFrame) {
+ wr.Write("...");
+ } else {
+ PrintFrameExpressionList(s.Mod.Expressions);
+ }
+ if (s.Body != null) {
+ // There's a possible syntactic ambiguity, namely if the frame is empty (more precisely,
+ // if s.Mod.Expressions.Count is 0). Since the statement was parsed at some point, this
+ // situation can occur only if the modify statement inherited its frame by refinement
+ // and we're printing the post-resolve AST. In this special case, print an explicit
+ // empty set as the frame.
+ if (s.Mod.Expressions.Count == 0) {
+ wr.Write(" {}");
+ }
+ wr.Write(" ");
+ PrintStatement(s.Body, indent);
+ } else {
+ wr.Write(";");
+ }
+ }
+
+ /// <summary>
+ /// Does not print LHS
+ /// </summary>
+ void PrintUpdateRHS(ConcreteUpdateStatement s) {
+ Contract.Requires(s != null);
+ if (s is UpdateStmt) {
+ var update = (UpdateStmt)s;
+ if (update.Lhss.Count != 0) {
+ wr.Write(" := ");
+ }
+ var sep = "";
+ foreach (var rhs in update.Rhss) {
+ wr.Write(sep);
+ PrintRhs(rhs);
+ sep = ", ";
+ }
+ } else if (s is AssignSuchThatStmt) {
+ var update = (AssignSuchThatStmt)s;
+ wr.Write(" :| ");
+ if (update.AssumeToken != null) {
+ wr.Write("assume ");
+ }
+ PrintExpression(update.Expr, true);
+ } else {
+ Contract.Assert(s == null); // otherwise, unknown type
+ }
+ }
+
+ void PrintIfStatement(int indent, IfStmt s, bool omitGuard) {
+ if (omitGuard) {
+ wr.Write("if ... ");
+ } else {
+ wr.Write("if ");
+ PrintGuard(s.IsExistentialGuard, s.Guard);
+ wr.Write(" ");
+ }
+ PrintStatement(s.Thn, indent);
+ if (s.Els != null) {
wr.Write(" else ");
- if (s.Els is IfStmt) {
- s = (IfStmt)s.Els;
- } else {
- PrintStatement(s.Els, indent);
- break;
- }
- }
- }
-
- void PrintWhileStatement(int indent, WhileStmt s, bool omitGuard, bool omitBody) {
- Contract.Requires(0 <= indent);
- if (omitGuard) {
- wr.WriteLine("while ...");
- } else {
- wr.Write("while ");
- PrintGuard(s.Guard);
- wr.WriteLine();
- }
-
- PrintSpec("invariant", s.Invariants, indent + IndentAmount, s.Body != null || omitBody || (s.Decreases.Expressions != null && s.Decreases.Expressions.Count != 0) || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));
- PrintDecreasesSpec(s.Decreases, indent + IndentAmount, s.Body != null || omitBody || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));
- if (s.Mod.Expressions != null) {
- PrintFrameSpecLine("modifies", s.Mod.Expressions, indent + IndentAmount, s.Mod.HasAttributes() ? s.Mod.Attributes : null, s.Body != null || omitBody);
- }
- Indent(indent);
- if (omitBody) {
- wr.WriteLine("...;");
- } else if (s.Body != null) {
- PrintStatement(s.Body, indent);
- }
- }
-
- void PrintAlternatives(int indent, List<GuardedAlternative> alternatives) {
- int caseInd = indent + IndentAmount;
- foreach (var alternative in alternatives) {
- Indent(caseInd);
+ PrintStatement(s.Els, indent);
+ }
+ }
+
+ void PrintWhileStatement(int indent, WhileStmt s, bool omitGuard, bool omitBody) {
+ Contract.Requires(0 <= indent);
+ if (omitGuard) {
+ wr.WriteLine("while ...");
+ } else {
+ wr.Write("while ");
+ PrintGuard(false, s.Guard);
+ wr.WriteLine();
+ }
+
+ PrintSpec("invariant", s.Invariants, indent + IndentAmount, s.Body != null || omitBody || (s.Decreases.Expressions != null && s.Decreases.Expressions.Count != 0) || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));
+ PrintDecreasesSpec(s.Decreases, indent + IndentAmount, s.Body != null || omitBody || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));
+ if (s.Mod.Expressions != null) {
+ PrintFrameSpecLine("modifies", s.Mod.Expressions, indent + IndentAmount, s.Mod.HasAttributes() ? s.Mod.Attributes : null, s.Body != null || omitBody);
+ }
+ Indent(indent);
+ if (omitBody) {
+ wr.WriteLine("...;");
+ } else if (s.Body != null) {
+ PrintStatement(s.Body, indent);
+ }
+ }
+
+ void PrintAlternatives(int indent, List<GuardedAlternative> alternatives) {
+ int caseInd = indent + IndentAmount;
+ foreach (var alternative in alternatives) {
+ Indent(caseInd);
wr.Write("case ");
- PrintExpression(alternative.Guard, false);
- wr.WriteLine(" =>");
- foreach (Statement s in alternative.Body) {
- Indent(caseInd + IndentAmount);
- PrintStatement(s, caseInd + IndentAmount);
- wr.WriteLine();
- }
- }
- }
-
- void PrintRhs(AssignmentRhs rhs) {
- Contract.Requires(rhs != null);
- if (rhs is ExprRhs) {
- PrintExpression(((ExprRhs)rhs).Expr, true);
- } else if (rhs is HavocRhs) {
- wr.Write("*");
- } else if (rhs is TypeRhs) {
- TypeRhs t = (TypeRhs)rhs;
- wr.Write("new ");
- if (t.ArrayDimensions != null) {
- PrintType(t.EType);
- string s = "[";
- foreach (Expression dim in t.ArrayDimensions) {
- Contract.Assume(dim != null);
- wr.Write(s);
- PrintExpression(dim, false);
- s = ", ";
- }
- wr.Write("]");
- } else if (t.Arguments == null) {
- PrintType(t.EType);
- } else {
- PrintType(t.Path);
- wr.Write("(");
- PrintExpressionList(t.Arguments, false);
- wr.Write(")");
- }
- } else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected RHS
- }
-
- if (rhs.HasAttributes())
- {
- PrintAttributes(rhs.Attributes);
- }
- }
-
- void PrintGuard(Expression guard) {
- if (guard == null) {
- wr.Write("*");
- } else {
- PrintExpression(guard, false);
- }
- }
-
- void PrintCalcOp(CalcStmt.CalcOp op) {
- Contract.Requires(op != null);
- wr.Write(op.ToString());
- if (op is CalcStmt.TernaryCalcOp) {
- wr.Write("[");
- PrintExpression(((CalcStmt.TernaryCalcOp) op).Index, false);
- wr.Write("]");
- }
- }
-
- // ----------------------------- PrintExpression -----------------------------
-
- /// <summary>
- /// PrintExtendedExpr prints an expression, but formats top-level if-then-else and match expressions across several lines.
- /// Its intended use is thus to print the body of a function.
- /// </summary>
- public void PrintExtendedExpr(Expression expr, int indent, bool isRightmost, bool endWithCloseParen) {
- Contract.Requires(expr != null);
- if (expr is ITEExpr) {
- Indent(indent);
- while (true) {
- var ite = (ITEExpr)expr;
- wr.Write("if ");
- PrintExpression(ite.Test, false);
- wr.WriteLine(" then");
- PrintExtendedExpr(ite.Thn, indent + IndentAmount, true, false);
- expr = ite.Els;
- if (expr is ITEExpr) {
- Indent(indent); wr.Write("else ");
- } else {
- Indent(indent); wr.WriteLine("else");
- Indent(indent + IndentAmount);
- PrintExpression(expr, isRightmost, false);
- wr.WriteLine(endWithCloseParen ? ")" : "");
- return;
- }
- }
- } else if (expr is MatchExpr) {
- var e = (MatchExpr)expr;
- Indent(indent);
- var parensNeeded = !isRightmost && !e.UsesOptionalBraces;
- if (parensNeeded) { wr.Write("("); }
- wr.Write("match ");
- PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, false);
- if (e.UsesOptionalBraces) { wr.WriteLine(" {"); }
- else if (parensNeeded && e.Cases.Count == 0) { wr.WriteLine(")"); }
- else { wr.WriteLine(); }
- int i = 0;
- int ind = indent + (e.UsesOptionalBraces ? IndentAmount : 0);
- foreach (var mc in e.Cases) {
- bool isLastCase = i == e.Cases.Count - 1;
- Indent(ind);
- wr.Write("case {0}", mc.Id);
- if (mc.Arguments.Count != 0) {
- string sep = "(";
- foreach (BoundVar bv in mc.Arguments) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- if (bv.Type is NonProxyType) {
- wr.Write(": {0}", bv.Type);
- }
- sep = ", ";
- }
- wr.Write(")");
- }
- wr.WriteLine(" =>");
- PrintExtendedExpr(mc.Body, ind + IndentAmount, isLastCase, isLastCase && (parensNeeded || endWithCloseParen));
- i++;
- }
- if (e.UsesOptionalBraces) {
- Indent(indent);
- wr.WriteLine("}");
- }
- } else if (expr is LetExpr) {
- var e = (LetExpr)expr;
- Indent(indent);
- wr.Write("var ");
- string sep = "";
- foreach (var lhs in e.LHSs) {
- wr.Write(sep);
- PrintCasePattern(lhs);
- sep = ", ";
- }
- if (e.Exact) {
- wr.Write(" := ");
+ if (alternative.IsExistentialGuard) {
+ var exists = (ExistsExpr)alternative.Guard;
+ PrintExistentialGuard(exists);
} else {
- wr.Write(" :| ");
- }
- PrintExpressionList(e.RHSs, true);
- wr.WriteLine(";");
- PrintExtendedExpr(e.Body, indent, isRightmost, endWithCloseParen);
-
- } else if (expr is ParensExpression) {
- PrintExtendedExpr(((ParensExpression)expr).E, indent, isRightmost, endWithCloseParen);
- } else {
- Indent(indent);
- PrintExpression(expr, false, indent);
- wr.WriteLine(endWithCloseParen ? ")" : "");
- }
+ PrintExpression(alternative.Guard, false);
+ }
+ wr.WriteLine(" =>");
+ foreach (Statement s in alternative.Body) {
+ Indent(caseInd + IndentAmount);
+ PrintStatement(s, caseInd + IndentAmount);
+ wr.WriteLine();
+ }
+ }
+ }
+
+ void PrintRhs(AssignmentRhs rhs) {
+ Contract.Requires(rhs != null);
+ if (rhs is ExprRhs) {
+ PrintExpression(((ExprRhs)rhs).Expr, true);
+ } else if (rhs is HavocRhs) {
+ wr.Write("*");
+ } else if (rhs is TypeRhs) {
+ TypeRhs t = (TypeRhs)rhs;
+ wr.Write("new ");
+ if (t.ArrayDimensions != null) {
+ PrintType(t.EType);
+ string s = "[";
+ foreach (Expression dim in t.ArrayDimensions) {
+ Contract.Assume(dim != null);
+ wr.Write(s);
+ PrintExpression(dim, false);
+ s = ", ";
+ }
+ wr.Write("]");
+ } else if (t.Arguments == null) {
+ PrintType(t.EType);
+ } else {
+ PrintType(t.Path);
+ wr.Write("(");
+ PrintExpressionList(t.Arguments, false);
+ wr.Write(")");
+ }
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected RHS
+ }
+
+ if (rhs.HasAttributes())
+ {
+ PrintAttributes(rhs.Attributes);
+ }
+ }
+
+ void PrintGuard(bool isExistentialGuard, Expression guard) {
+ Contract.Requires(!isExistentialGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));
+ if (guard == null) {
+ wr.Write("*");
+ } else if (isExistentialGuard) {
+ var exists = (ExistsExpr)guard;
+ PrintExistentialGuard(exists);
+ } else {
+ PrintExpression(guard, false);
+ }
}
- public void PrintExpression(Expression expr, bool isFollowedBySemicolon) {
- Contract.Requires(expr != null);
- PrintExpr(expr, 0, false, true, isFollowedBySemicolon, -1);
+ void PrintExistentialGuard(ExistsExpr guard) {
+ Contract.Requires(guard != null);
+ Contract.Requires(guard.Range == null);
+ PrintQuantifierDomain(guard.BoundVars, guard.Attributes, null);
+ wr.Write(" :| ");
+ PrintExpression(guard.Term, false);
+ }
+
+ void PrintCalcOp(CalcStmt.CalcOp op) {
+ Contract.Requires(op != null);
+ wr.Write(op.ToString());
+ if (op is CalcStmt.TernaryCalcOp) {
+ wr.Write("[");
+ PrintExpression(((CalcStmt.TernaryCalcOp) op).Index, false);
+ wr.Write("]");
+ }
+ }
+
+ // ----------------------------- PrintExpression -----------------------------
+
+ /// <summary>
+ /// PrintExtendedExpr prints an expression, but formats top-level if-then-else and match expressions across several lines.
+ /// Its intended use is thus to print the body of a function.
+ /// </summary>
+ public void PrintExtendedExpr(Expression expr, int indent, bool isRightmost, bool endWithCloseParen) {
+ Contract.Requires(expr != null);
+ if (expr is ITEExpr) {
+ Indent(indent);
+ while (true) {
+ var ite = (ITEExpr)expr;
+ wr.Write("if ");
+ PrintExpression(ite.Test, false);
+ wr.WriteLine(" then");
+ PrintExtendedExpr(ite.Thn, indent + IndentAmount, true, false);
+ expr = ite.Els;
+ if (expr is ITEExpr) {
+ Indent(indent); wr.Write("else ");
+ } else {
+ Indent(indent); wr.WriteLine("else");
+ Indent(indent + IndentAmount);
+ PrintExpression(expr, isRightmost, false);
+ wr.WriteLine(endWithCloseParen ? ")" : "");
+ return;
+ }
+ }
+ } else if (expr is MatchExpr) {
+ var e = (MatchExpr)expr;
+ Indent(indent);
+ var parensNeeded = !isRightmost && !e.UsesOptionalBraces;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("match ");
+ PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, false);
+ if (e.UsesOptionalBraces) { wr.WriteLine(" {"); }
+ else if (parensNeeded && e.Cases.Count == 0) { wr.WriteLine(")"); }
+ else { wr.WriteLine(); }
+ int i = 0;
+ int ind = indent + (e.UsesOptionalBraces ? IndentAmount : 0);
+ foreach (var mc in e.Cases) {
+ bool isLastCase = i == e.Cases.Count - 1;
+ Indent(ind);
+ wr.Write("case {0}", mc.Id);
+ PrintMatchCaseArgument(mc);
+ wr.WriteLine(" =>");
+ PrintExtendedExpr(mc.Body, ind + IndentAmount, isLastCase, isLastCase && (parensNeeded || endWithCloseParen));
+ i++;
+ }
+ if (e.UsesOptionalBraces) {
+ Indent(indent);
+ wr.WriteLine("}");
+ }
+ } else if (expr is LetExpr) {
+ var e = (LetExpr)expr;
+ Indent(indent);
+ wr.Write("var ");
+ string sep = "";
+ foreach (var lhs in e.LHSs) {
+ wr.Write(sep);
+ PrintCasePattern(lhs);
+ sep = ", ";
+ }
+ if (e.Exact) {
+ wr.Write(" := ");
+ } else {
+ wr.Write(" :| ");
+ }
+ PrintExpressionList(e.RHSs, true);
+ wr.WriteLine(";");
+ PrintExtendedExpr(e.Body, indent, isRightmost, endWithCloseParen);
+
+ } else if (expr is ParensExpression) {
+ PrintExtendedExpr(((ParensExpression)expr).E, indent, isRightmost, endWithCloseParen);
+ } else {
+ Indent(indent);
+ PrintExpression(expr, false, indent);
+ wr.WriteLine(endWithCloseParen ? ")" : "");
+ }
+ }
+
+ public void PrintMatchCaseArgument(MatchCase mc) {
+ if (mc.Arguments != null) {
+ if (mc.Arguments.Count != 0) {
+ string sep = "(";
+ foreach (BoundVar bv in mc.Arguments) {
+ wr.Write("{0}{1}", sep, bv.DisplayName);
+ if (bv.Type is NonProxyType) {
+ wr.Write(": {0}", bv.Type);
+ }
+ sep = ", ";
+ }
+ wr.Write(")");
+ }
+ } else {
+ Contract.Assert(mc.CasePatterns != null);
+ if (mc.CasePatterns.Count != 0) {
+ string sep = "(";
+ foreach (var cp in mc.CasePatterns) {
+ wr.Write(sep);
+ PrintCasePattern(cp);
+ sep = ", ";
+ }
+ wr.Write(")");
+ }
+ }
+ }
+
+ public void PrintExpression(Expression expr, bool isFollowedBySemicolon) {
+ Contract.Requires(expr != null);
+ PrintExpr(expr, 0, false, true, isFollowedBySemicolon, -1);
+ }
+
+ public void PrintExpression(Expression expr, bool isRightmost, bool isFollowedBySemicolon) {
+ Contract.Requires(expr != null);
+ PrintExpr(expr, 0, false, isRightmost, isFollowedBySemicolon, -1);
+ }
+
+ /// <summary>
+ /// An indent of -1 means print the entire expression on one line.
+ /// </summary>
+ public void PrintExpression(Expression expr, bool isFollowedBySemicolon, int indent) {
+ Contract.Requires(expr != null);
+ PrintExpr(expr, 0, false, true, isFollowedBySemicolon, indent);
}
- public void PrintExpression(Expression expr, bool isRightmost, bool isFollowedBySemicolon) {
+ public void PrintExpression(Expression expr, bool isFollowedBySemicolon, string keyword) {
Contract.Requires(expr != null);
- PrintExpr(expr, 0, false, isRightmost, isFollowedBySemicolon, -1);
- }
-
- /// <summary>
- /// An indent of -1 means print the entire expression on one line.
- /// </summary>
- public void PrintExpression(Expression expr, bool isFollowedBySemicolon, int indent) {
- Contract.Requires(expr != null);
- PrintExpr(expr, 0, false, true, isFollowedBySemicolon, indent);
- }
-
- /// <summary>
- /// An indent of -1 means print the entire expression on one line.
- /// </summary>
- void PrintExpr(Expression expr, int contextBindingStrength, bool fragileContext, bool isRightmost, bool isFollowedBySemicolon, int indent, int resolv_count = 2)
- {
- Contract.Requires(-1 <= indent);
- Contract.Requires(expr != null);
-
- /* When debugging:
- if (resolv_count > 0 && expr.Resolved != null) {
- PrintExpr(expr.Resolved, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, resolv_count - 1);
- return;
- }
- */
-
- if (expr is StaticReceiverExpr) {
- StaticReceiverExpr e = (StaticReceiverExpr)expr;
- wr.Write(e.Type);
- } else if (expr is LiteralExpr) {
- LiteralExpr e = (LiteralExpr)expr;
- if (e.Value == null) {
- wr.Write("null");
- } else if (e.Value is bool) {
- wr.Write((bool)e.Value ? "true" : "false");
- } else if (e is CharLiteralExpr) {
- wr.Write("'{0}'", (string)e.Value);
- } else if (e is StringLiteralExpr) {
- var str = (StringLiteralExpr)e;
- wr.Write("{0}\"{1}\"", str.IsVerbatim ? "@" : "", (string)e.Value);
- } else if (e.Value is Basetypes.BigDec) {
- Basetypes.BigDec dec = (Basetypes.BigDec)e.Value;
- wr.Write((dec.Mantissa >= 0) ? "" : "-");
- string s = BigInteger.Abs(dec.Mantissa).ToString();
- int digits = s.Length;
- if (dec.Exponent >= 0) {
- wr.Write("{0}{1}.0", s, new string('0', dec.Exponent));
- } else {
- int exp = -dec.Exponent;
- if (exp < digits) {
- int intDigits = digits - exp;
- int fracDigits = digits - intDigits;
- wr.Write("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits));
- } else {
- int fracDigits = digits;
- wr.Write("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits));
- }
- }
- } else {
- wr.Write((BigInteger)e.Value);
- }
-
- } else if (expr is ThisExpr) {
- wr.Write("this");
-
- } else if (expr is IdentifierExpr) {
- wr.Write(((IdentifierExpr)expr).Name);
-
- } else if (expr is DatatypeValue) {
- var dtv = (DatatypeValue)expr;
- bool printParens;
- if (dtv.MemberName == BuiltIns.TupleTypeCtorName) {
- // we're looking at a tuple, whose printed constructor name is essentially the empty string
- printParens = true;
- } else {
- wr.Write("{0}.{1}", dtv.DatatypeName, dtv.MemberName);
- printParens = dtv.Arguments.Count != 0;
- }
- if (printParens) {
- wr.Write("(");
- PrintExpressionList(dtv.Arguments, false);
- wr.Write(")");
- }
-
- } else if (expr is DisplayExpression) {
- DisplayExpression e = (DisplayExpression)expr;
- if (e is MultiSetDisplayExpr) wr.Write("multiset");
- wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "{" : "[");
- PrintExpressionList(e.Elements, false);
- wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "}" : "]");
-
- } else if (expr is MapDisplayExpr) {
- MapDisplayExpr e = (MapDisplayExpr)expr;
- wr.Write(e.Finite ? "map" : "imap");
- wr.Write("[");
- PrintExpressionPairList(e.Elements);
- wr.Write("]");
-
- } else if (expr is NameSegment) {
- var e = (NameSegment)expr;
- wr.Write(e.Name);
- PrintTypeInstantiation(e.OptTypeArguments);
-
- } else if (expr is ExprDotName) {
- var e = (ExprDotName)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = !(e.Lhs is ImplicitThisExpr) &&
- opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- if (parensNeeded) { wr.Write("("); }
- if (!(e.Lhs is ImplicitThisExpr)) {
- PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1);
- wr.Write(".");
- }
- wr.Write(e.SuffixName);
- PrintTypeInstantiation(e.OptTypeArguments);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is ApplySuffix) {
- var e = (ApplySuffix)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = !(e.Lhs is ImplicitThisExpr) &&
- opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- if (parensNeeded) { wr.Write("("); }
- if (ParensMayMatter(e.Lhs)) {
- wr.Write("(");
- PrintExpression(e.Lhs, false);
- wr.Write(")");
+ PrintExpr(expr, 0, false, true, isFollowedBySemicolon, -1, keyword);
+ }
+
+ private bool ParensNeeded(int opBindingStrength, int contextBindingStrength, bool fragileContext) {
+ return opBindingStrength < contextBindingStrength ||
+ (fragileContext && opBindingStrength == contextBindingStrength);
+ }
+
+ /// <summary>
+ /// An indent of -1 means print the entire expression on one line.
+ /// </summary>
+ void PrintExpr(Expression expr, int contextBindingStrength, bool fragileContext, bool isRightmost, bool isFollowedBySemicolon, int indent, string keyword = null, int resolv_count = 2 )
+ {
+ Contract.Requires(-1 <= indent);
+ Contract.Requires(expr != null);
+
+ /* When debugging:
+ if (resolv_count > 0 && expr.Resolved != null) {
+ PrintExpr(expr.Resolved, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, resolv_count - 1);
+ return;
+ }
+ */
+
+ if (expr is StaticReceiverExpr) {
+ StaticReceiverExpr e = (StaticReceiverExpr)expr;
+ wr.Write(e.Type);
+ } else if (expr is LiteralExpr) {
+ LiteralExpr e = (LiteralExpr)expr;
+ if (e.Value == null) {
+ wr.Write("null");
+ } else if (e.Value is bool) {
+ wr.Write((bool)e.Value ? "true" : "false");
+ } else if (e is CharLiteralExpr) {
+ wr.Write("'{0}'", (string)e.Value);
+ } else if (e is StringLiteralExpr) {
+ var str = (StringLiteralExpr)e;
+ wr.Write("{0}\"{1}\"", str.IsVerbatim ? "@" : "", (string)e.Value);
+ } else if (e.Value is Basetypes.BigDec) {
+ Basetypes.BigDec dec = (Basetypes.BigDec)e.Value;
+ wr.Write((dec.Mantissa >= 0) ? "" : "-");
+ string s = BigInteger.Abs(dec.Mantissa).ToString();
+ int digits = s.Length;
+ if (dec.Exponent >= 0) {
+ wr.Write("{0}{1}.0", s, new string('0', dec.Exponent));
+ } else {
+ int exp = -dec.Exponent;
+ if (exp < digits) {
+ int intDigits = digits - exp;
+ int fracDigits = digits - intDigits;
+ wr.Write("{0}.{1}", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits));
+ } else {
+ int fracDigits = digits;
+ wr.Write("0.{0}{1}", new string('0', exp - fracDigits), s.Substring(0, fracDigits));
+ }
+ }
+ } else {
+ wr.Write((BigInteger)e.Value);
+ }
+
+ } else if (expr is ThisExpr) {
+ wr.Write("this");
+
+ } else if (expr is IdentifierExpr) {
+ wr.Write(((IdentifierExpr)expr).Name);
+
+ } else if (expr is DatatypeValue) {
+ var dtv = (DatatypeValue)expr;
+ bool printParens;
+ if (dtv.MemberName == BuiltIns.TupleTypeCtorName) {
+ // we're looking at a tuple, whose printed constructor name is essentially the empty string
+ printParens = true;
+ } else {
+ wr.Write("{0}.{1}", dtv.DatatypeName, dtv.MemberName);
+ printParens = dtv.Arguments.Count != 0;
+ }
+ if (printParens) {
+ wr.Write("(");
+ PrintExpressionList(dtv.Arguments, false);
+ wr.Write(")");
+ }
+
+ } else if (expr is DisplayExpression) {
+ DisplayExpression e = (DisplayExpression)expr;
+ if (e is MultiSetDisplayExpr) {
+ wr.Write("multiset");
+ } else if (e is SetDisplayExpr && !((SetDisplayExpr)e).Finite) {
+ wr.Write("iset");
+ }
+ wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "{" : "[");
+ PrintExpressionList(e.Elements, false);
+ wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? "}" : "]");
+
+ } else if (expr is MapDisplayExpr) {
+ MapDisplayExpr e = (MapDisplayExpr)expr;
+ wr.Write(e.Finite ? "map" : "imap");
+ wr.Write("[");
+ PrintExpressionPairList(e.Elements);
+ wr.Write("]");
+
+ } else if (expr is NameSegment) {
+ var e = (NameSegment)expr;
+ wr.Write(e.Name);
+ PrintTypeInstantiation(e.OptTypeArguments);
+
+ } else if (expr is ExprDotName) {
+ var e = (ExprDotName)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = !e.Lhs.IsImplicit && // KRML: I think that this never holds
+ ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ if (parensNeeded) { wr.Write("("); }
+ if (!e.Lhs.IsImplicit) {
+ PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ wr.Write(".");
+ }
+ wr.Write(e.SuffixName);
+ PrintTypeInstantiation(e.OptTypeArguments);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is ApplySuffix) {
+ var e = (ApplySuffix)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = !e.Lhs.IsImplicit && // KRML: I think that this never holds
+ ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ if (parensNeeded) { wr.Write("("); }
+ if (ParensMayMatter(e.Lhs)) {
+ wr.Write("(");
+ PrintExpression(e.Lhs, false);
+ wr.Write(")");
} else {
- PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1);
- }
- wr.Write("(");
- PrintExpressionList(e.Args, false);
- wr.Write(")");
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is MemberSelectExpr) {
- MemberSelectExpr e = (MemberSelectExpr)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = !(e.Obj is ImplicitThisExpr) &&
- opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- if (parensNeeded) { wr.Write("("); }
- if (!(e.Obj is ImplicitThisExpr)) {
- PrintExpr(e.Obj, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1);
- wr.Write(".");
- }
- wr.Write(e.MemberName);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is SeqSelectExpr) {
- SeqSelectExpr e = (SeqSelectExpr)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
+ PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ }
+ wr.Write("(");
+ PrintExpressionList(e.Args, false);
+ wr.Write(")");
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is MemberSelectExpr) {
+ MemberSelectExpr e = (MemberSelectExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = !e.Obj.IsImplicit &&
+ ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ if (parensNeeded) { wr.Write("("); }
+ if (!(e.Obj.IsImplicit)) {
+ PrintExpr(e.Obj, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ wr.Write(".");
+ }
+ wr.Write(e.MemberName);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is SeqSelectExpr) {
+ SeqSelectExpr e = (SeqSelectExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
if (parensNeeded) { wr.Write("("); }
- PrintExpr(e.Seq, 0x00, false, false, !parensNeeded && isFollowedBySemicolon, indent); // BOGUS: fix me
- wr.Write("[");
- if (e.SelectOne) {
- Contract.Assert( e.E0 != null);
- PrintExpression(e.E0, false);
- } else {
- if (e.E0 != null) {
- PrintExpression(e.E0, false);
- }
- wr.Write(e.E0 != null && e.E1 != null ? " .. " : "..");
- if (e.E1 != null) {
- PrintExpression(e.E1, false);
- }
- }
- wr.Write("]");
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is MultiSelectExpr) {
- MultiSelectExpr e = (MultiSelectExpr)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
+ PrintExpr(e.Seq, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);
+ wr.Write("[");
+ if (e.SelectOne) {
+ Contract.Assert( e.E0 != null);
+ PrintExpression(e.E0, false);
+ } else {
+ if (e.E0 != null) {
+ PrintExpression(e.E0, false);
+ }
+ wr.Write(e.E0 != null && e.E1 != null ? " .. " : "..");
+ if (e.E1 != null) {
+ PrintExpression(e.E1, false);
+ }
+ }
+ wr.Write("]");
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is MultiSelectExpr) {
+ MultiSelectExpr e = (MultiSelectExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
if (parensNeeded) { wr.Write("("); }
- PrintExpr(e.Array, 0x00, false, false, !parensNeeded && isFollowedBySemicolon, indent); // BOGUS: fix me
- string prefix = "[";
- foreach (Expression idx in e.Indices) {
- Contract.Assert(idx != null);
- wr.Write(prefix);
- PrintExpression(idx, false);
- prefix = ", ";
- }
- wr.Write("]");
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is SeqUpdateExpr) {
- SeqUpdateExpr e = (SeqUpdateExpr)expr;
- if (e.ResolvedUpdateExpr != null)
- {
- PrintExpr(e.ResolvedUpdateExpr, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent);
- }
- else
+ PrintExpr(e.Array, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);
+ string prefix = "[";
+ foreach (Expression idx in e.Indices) {
+ Contract.Assert(idx != null);
+ wr.Write(prefix);
+ PrintExpression(idx, false);
+ prefix = ", ";
+ }
+ wr.Write("]");
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is SeqUpdateExpr) {
+ SeqUpdateExpr e = (SeqUpdateExpr)expr;
+ if (e.ResolvedUpdateExpr != null)
{
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded = opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
+ PrintExpr(e.ResolvedUpdateExpr, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);
+ }
+ else
+ {
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
if (parensNeeded) { wr.Write("("); }
- PrintExpr(e.Seq, 00, false, false, !parensNeeded && isFollowedBySemicolon, indent); // BOGUS: fix me
- wr.Write("[");
- PrintExpression(e.Index, false);
- wr.Write(" := ");
- PrintExpression(e.Value, false);
- wr.Write("]");
- if (parensNeeded) { wr.Write(")"); }
+ PrintExpr(e.Seq, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);
+ wr.Write("[");
+ PrintExpression(e.Index, false);
+ wr.Write(" := ");
+ PrintExpression(e.Value, false);
+ wr.Write("]");
+ if (parensNeeded) { wr.Write(")"); }
}
- } else if (expr is ApplyExpr) {
- var e = (ApplyExpr)expr;
- // determine if parens are needed
- int opBindingStrength = 0x70;
- bool parensNeeded =
- opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- if (parensNeeded) { wr.Write("("); }
- PrintExpr(e.Function, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1);
- wr.Write("(");
- PrintExpressionList(e.Args, false);
- wr.Write(")");
-
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is FunctionCallExpr) {
- var e = (FunctionCallExpr)expr;
+ } else if (expr is DatatypeUpdateExpr) {
+ var e = (DatatypeUpdateExpr)expr;
// determine if parens are needed
int opBindingStrength = 0x70;
- bool parensNeeded = !(e.Receiver is ImplicitThisExpr) &&
- opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
if (parensNeeded) { wr.Write("("); }
- if (!(e.Receiver is ImplicitThisExpr)) {
- PrintExpr(e.Receiver, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1);
- wr.Write(".");
- }
- wr.Write(e.Name);
- /* When debugging, this is nice to have:
- if (e.TypeArgumentSubstitutions.Count > 0) {
- wr.Write("[");
- wr.Write(Util.Comma(",", e.TypeArgumentSubstitutions, kv => kv.Key.FullName() + "->" + kv.Value));
- wr.Write("]");
- }
- */
- if (e.OpenParen == null && e.Args.Count == 0) {
- } else {
- PrintActualArguments(e.Args, e.Name);
+ PrintExpr(e.Root, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);
+ wr.Write(".(");
+ var sep = "";
+ foreach (var update in e.Updates) {
+ wr.Write("{0}{1} := ", sep, update.Item2);
+ PrintExpression(update.Item3, false);
+ sep = ", ";
}
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is OldExpr) {
- wr.Write("old(");
- PrintExpression(((OldExpr)expr).E, false);
wr.Write(")");
+ if (parensNeeded) { wr.Write(")"); }
- } else if (expr is MultiSetFormingExpr) {
- wr.Write("multiset(");
- PrintExpression(((MultiSetFormingExpr)expr).E, false);
- wr.Write(")");
-
- } else if (expr is UnaryOpExpr) {
- var e = (UnaryOpExpr)expr;
- if (e.Op == UnaryOpExpr.Opcode.Cardinality) {
- wr.Write("|");
- PrintExpression(e.E, false);
- wr.Write("|");
- } else if (e.Op == UnaryOpExpr.Opcode.Fresh) {
- wr.Write("fresh(");
- PrintExpression(e.E, false);
- wr.Write(")");
- } else {
- // Prefix operator.
- // determine if parens are needed
- string op;
- int opBindingStrength;
- switch (e.Op) {
- case UnaryOpExpr.Opcode.Not:
- op = "!"; opBindingStrength = 0x60; break;
- default:
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected unary opcode
- }
- bool parensNeeded = opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- bool containsNestedNot = e.E is ParensExpression &&
- ((ParensExpression)e.E).E is UnaryExpr &&
- ((UnaryOpExpr)((ParensExpression)e.E).E).Op == UnaryOpExpr.Opcode.Not;
+ } else if (expr is ApplyExpr) {
+ var e = (ApplyExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ if (parensNeeded) { wr.Write("("); }
- if (parensNeeded) { wr.Write("("); }
+ PrintExpr(e.Function, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ wr.Write("(");
+ PrintExpressionList(e.Args, false);
+ wr.Write(")");
+
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is FunctionCallExpr) {
+ var e = (FunctionCallExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x70;
+ bool parensNeeded = !(e.Receiver.IsImplicit) &&
+ ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ if (parensNeeded) { wr.Write("("); }
+ if (!e.Receiver.IsImplicit) {
+ PrintExpr(e.Receiver, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ wr.Write(".");
+ }
+ wr.Write(e.Name);
+ /* When debugging, this is nice to have:
+ if (e.TypeArgumentSubstitutions.Count > 0) {
+ wr.Write("[");
+ wr.Write(Util.Comma(",", e.TypeArgumentSubstitutions, kv => kv.Key.FullName() + "->" + kv.Value));
+ wr.Write("]");
+ }
+ */
+ if (e.OpenParen == null && e.Args.Count == 0) {
+ } else {
+ PrintActualArguments(e.Args, e.Name);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is OldExpr) {
+ wr.Write("old(");
+ PrintExpression(((OldExpr)expr).E, false);
+ wr.Write(")");
+
+ } else if (expr is MultiSetFormingExpr) {
+ wr.Write("multiset(");
+ PrintExpression(((MultiSetFormingExpr)expr).E, false);
+ wr.Write(")");
+
+ } else if (expr is UnaryOpExpr) {
+ var e = (UnaryOpExpr)expr;
+ if (e.Op == UnaryOpExpr.Opcode.Cardinality) {
+ wr.Write("|");
+ PrintExpression(e.E, false);
+ wr.Write("|");
+ } else if (e.Op == UnaryOpExpr.Opcode.Fresh) {
+ wr.Write("fresh(");
+ PrintExpression(e.E, false);
+ wr.Write(")");
+ } else {
+ // Prefix operator.
+ // determine if parens are needed
+ string op;
+ int opBindingStrength;
+ switch (e.Op) {
+ case UnaryOpExpr.Opcode.Not:
+ op = "!"; opBindingStrength = 0x60; break;
+ default:
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected unary opcode
+ }
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ bool containsNestedNot = e.E is ParensExpression &&
+ ((ParensExpression)e.E).E is UnaryExpr &&
+ ((UnaryOpExpr)((ParensExpression)e.E).E).Op == UnaryOpExpr.Opcode.Not;
+
+ if (parensNeeded) { wr.Write("("); }
wr.Write(op);
- PrintExpr(e.E, opBindingStrength, containsNestedNot, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1);
- if (parensNeeded) { wr.Write(")"); }
- }
-
- } else if (expr is ConversionExpr) {
- var e = (ConversionExpr)expr;
- PrintType(e.ToType);
- wr.Write("(");
- PrintExpression(e.E, false);
- wr.Write(")");
-
- } else if (expr is BinaryExpr) {
- BinaryExpr e = (BinaryExpr)expr;
- // determine if parens are needed
- int opBindingStrength;
- bool fragileLeftContext = false; // false means "allow same binding power on left without parens"
- bool fragileRightContext = false; // false means "allow same binding power on right without parens"
- switch (e.Op)
- {
- case BinaryExpr.Opcode.Add:
- opBindingStrength = 0x40; break;
- case BinaryExpr.Opcode.Sub:
- opBindingStrength = 0x40; fragileRightContext = true; break;
- case BinaryExpr.Opcode.Mul:
- opBindingStrength = 0x50; break;
- case BinaryExpr.Opcode.Div:
- case BinaryExpr.Opcode.Mod:
- opBindingStrength = 0x50; fragileRightContext = true; break;
- case BinaryExpr.Opcode.Eq:
- case BinaryExpr.Opcode.Neq:
- case BinaryExpr.Opcode.Gt:
- case BinaryExpr.Opcode.Ge:
- case BinaryExpr.Opcode.Lt:
- case BinaryExpr.Opcode.Le:
- case BinaryExpr.Opcode.Disjoint:
- case BinaryExpr.Opcode.In:
- case BinaryExpr.Opcode.NotIn:
- opBindingStrength = 0x30; fragileLeftContext = fragileRightContext = true; break;
- case BinaryExpr.Opcode.And:
- opBindingStrength = 0x20; break;
- case BinaryExpr.Opcode.Or:
- opBindingStrength = 0x21; break;
- case BinaryExpr.Opcode.Imp:
- opBindingStrength = 0x10; fragileLeftContext = true; break;
- case BinaryExpr.Opcode.Exp:
- opBindingStrength = 0x11; fragileRightContext = true; break;
- case BinaryExpr.Opcode.Iff:
- opBindingStrength = 0x08; break;
- default:
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected binary operator
- }
- int opBS = opBindingStrength & 0xF8;
- int ctxtBS = contextBindingStrength & 0xF8;
- bool parensNeeded = opBS < ctxtBS ||
- (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
-
- string op = BinaryExpr.OpcodeString(e.Op);
- if (parensNeeded) { wr.Write("("); }
- var sem = !parensNeeded && isFollowedBySemicolon;
+ PrintExpr(e.E, opBindingStrength, containsNestedNot, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ if (parensNeeded) { wr.Write(")"); }
+ }
+
+ } else if (expr is ConversionExpr) {
+ var e = (ConversionExpr)expr;
+ PrintType(e.ToType);
+ wr.Write("(");
+ PrintExpression(e.E, false);
+ wr.Write(")");
+
+ } else if (expr is BinaryExpr) {
+ BinaryExpr e = (BinaryExpr)expr;
+ // determine if parens are needed
+ int opBindingStrength;
+ bool fragileLeftContext = false; // false means "allow same binding power on left without parens"
+ bool fragileRightContext = false; // false means "allow same binding power on right without parens"
+ switch (e.Op)
+ {
+ case BinaryExpr.Opcode.Add:
+ opBindingStrength = 0x40; break;
+ case BinaryExpr.Opcode.Sub:
+ opBindingStrength = 0x40; fragileRightContext = true; break;
+ case BinaryExpr.Opcode.Mul:
+ opBindingStrength = 0x50; break;
+ case BinaryExpr.Opcode.Div:
+ case BinaryExpr.Opcode.Mod:
+ opBindingStrength = 0x50; fragileRightContext = true; break;
+ case BinaryExpr.Opcode.Eq:
+ case BinaryExpr.Opcode.Neq:
+ case BinaryExpr.Opcode.Gt:
+ case BinaryExpr.Opcode.Ge:
+ case BinaryExpr.Opcode.Lt:
+ case BinaryExpr.Opcode.Le:
+ case BinaryExpr.Opcode.Disjoint:
+ case BinaryExpr.Opcode.In:
+ case BinaryExpr.Opcode.NotIn:
+ opBindingStrength = 0x30; fragileLeftContext = fragileRightContext = true; break;
+ case BinaryExpr.Opcode.And:
+ opBindingStrength = 0x20; break;
+ case BinaryExpr.Opcode.Or:
+ opBindingStrength = 0x21; break;
+ case BinaryExpr.Opcode.Imp:
+ opBindingStrength = 0x10; fragileLeftContext = true; break;
+ case BinaryExpr.Opcode.Exp:
+ opBindingStrength = 0x11; fragileRightContext = true; break;
+ case BinaryExpr.Opcode.Iff:
+ opBindingStrength = 0x08; break;
+ default:
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected binary operator
+ }
+ int opBS = opBindingStrength & 0xF8;
+ int ctxtBS = contextBindingStrength & 0xF8;
+ bool parensNeeded = opBS < ctxtBS ||
+ (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
+
+ string op = BinaryExpr.OpcodeString(e.Op);
+ if (parensNeeded) { wr.Write("("); }
+ var sem = !parensNeeded && isFollowedBySemicolon;
if (0 <= indent && e.Op == BinaryExpr.Opcode.And) {
- PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent);
- wr.WriteLine(" {0}", op);
+ PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);
+ wr.WriteLine(" {0}", op);
Indent(indent);
- PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, indent);
+ PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, indent, keyword);
} else if (0 <= indent && e.Op == BinaryExpr.Opcode.Imp) {
- PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent);
- wr.WriteLine(" {0}", op);
- int ind = indent + IndentAmount;
+ PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);
+ wr.WriteLine(" {0}", op);
+ int ind = indent + IndentAmount;
Indent(ind);
- PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind);
+ PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind, keyword);
} else if (0 <= indent && e.Op == BinaryExpr.Opcode.Exp) {
- PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, indent);
- wr.WriteLine(" {0}", op);
- int ind = indent + IndentAmount;
+ PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);
+ wr.WriteLine(" {0}", op);
+ int ind = indent + IndentAmount;
Indent(ind);
- PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind);
- } else if (e.Op == BinaryExpr.Opcode.Exp) {
- PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1);
+ PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind, keyword);
+ } else if (e.Op == BinaryExpr.Opcode.Exp) {
+ PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);
wr.Write(" {0} ", op);
- PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1);
+ PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);
} else {
- PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, -1);
+ PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);
wr.Write(" {0} ", op);
- PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1);
- }
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is TernaryExpr) {
- var e = (TernaryExpr)expr;
- switch (e.Op) {
- case TernaryExpr.Opcode.PrefixEqOp:
- case TernaryExpr.Opcode.PrefixNeqOp:
- var opBindingStrength = 0x30;
- var fragileLeftContext = true;
- var fragileRightContext = true;
-
- int opBS = opBindingStrength & 0xF8;
- int ctxtBS = contextBindingStrength & 0xF8;
- bool parensNeeded = opBS < ctxtBS ||
- (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
-
- if (parensNeeded) { wr.Write("("); }
+ PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is TernaryExpr) {
+ var e = (TernaryExpr)expr;
+ switch (e.Op) {
+ case TernaryExpr.Opcode.PrefixEqOp:
+ case TernaryExpr.Opcode.PrefixNeqOp:
+ var opBindingStrength = 0x30;
+ var fragileLeftContext = true;
+ var fragileRightContext = true;
+
+ int opBS = opBindingStrength & 0xF8;
+ int ctxtBS = contextBindingStrength & 0xF8;
+ bool parensNeeded = opBS < ctxtBS ||
+ (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
+
+ if (parensNeeded) { wr.Write("("); }
var sem = !parensNeeded && isFollowedBySemicolon;
- PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1);
- wr.Write(" {0}#[", e.Op == TernaryExpr.Opcode.PrefixEqOp ? "==" : "!=");
- PrintExpression(e.E0, false);
+ PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);
+ wr.Write(" {0}#[", e.Op == TernaryExpr.Opcode.PrefixEqOp ? "==" : "!=");
+ PrintExpression(e.E0, false);
wr.Write("] ");
- PrintExpr(e.E2, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1);
- if (parensNeeded) { wr.Write(")"); }
- break;
- default:
- Contract.Assert(false); // unexpected ternary operator
- break;
- }
-
- } else if (expr is ChainingExpression) {
- var e = (ChainingExpression)expr;
- // determine if parens are needed
- int opBindingStrength = 0x30;
- int opBS = opBindingStrength & 0xF8;
- int ctxtBS = contextBindingStrength & 0xF8;
- bool parensNeeded = opBS < ctxtBS ||
- (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
-
- if (parensNeeded) { wr.Write("("); }
+ PrintExpr(e.E2, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);
+ if (parensNeeded) { wr.Write(")"); }
+ break;
+ default:
+ Contract.Assert(false); // unexpected ternary operator
+ break;
+ }
+
+ } else if (expr is ChainingExpression) {
+ var e = (ChainingExpression)expr;
+ // determine if parens are needed
+ int opBindingStrength = 0x30;
+ int opBS = opBindingStrength & 0xF8;
+ int ctxtBS = contextBindingStrength & 0xF8;
+ bool parensNeeded = opBS < ctxtBS ||
+ (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));
+
+ if (parensNeeded) { wr.Write("("); }
var sem = !parensNeeded && isFollowedBySemicolon;
- PrintExpr(e.Operands[0], opBindingStrength, true, false, sem, -1);
- for (int i = 0; i < e.Operators.Count; i++) {
- string op = BinaryExpr.OpcodeString(e.Operators[i]);
- if (e.PrefixLimits[i] == null) {
- wr.Write(" {0} ", op);
- } else {
- wr.Write(" {0}#[", op);
- PrintExpression(e.PrefixLimits[i], false);
- wr.Write("] ");
+ PrintExpr(e.Operands[0], opBindingStrength, true, false, sem, -1, keyword);
+ for (int i = 0; i < e.Operators.Count; i++) {
+ string op = BinaryExpr.OpcodeString(e.Operators[i]);
+ if (e.PrefixLimits[i] == null) {
+ wr.Write(" {0} ", op);
+ } else {
+ wr.Write(" {0}#[", op);
+ PrintExpression(e.PrefixLimits[i], false);
+ wr.Write("] ");
}
- PrintExpr(e.Operands[i+1], opBindingStrength, true, i == e.Operators.Count - 1 && (parensNeeded || isRightmost), sem, -1);
- }
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is LetExpr) {
- var e = (LetExpr)expr;
- bool parensNeeded = !isRightmost;
- if (parensNeeded) { wr.Write("("); }
- wr.Write("var ");
- string sep = "";
- foreach (var lhs in e.LHSs) {
- wr.Write(sep);
- PrintCasePattern(lhs);
- sep = ", ";
- }
- if (e.Exact) {
- wr.Write(" := ");
- } else {
- wr.Write(" :| ");
- }
- PrintExpressionList(e.RHSs, true);
- wr.Write("; ");
- PrintExpression(e.Body, !parensNeeded && isFollowedBySemicolon);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
- bool parensNeeded = !isRightmost;
- if (parensNeeded) { wr.Write("("); }
- wr.Write(e is ForallExpr ? "forall" : "exists");
- PrintTypeParams(e.TypeArgs); // new!
- wr.Write(" ");
+ PrintExpr(e.Operands[i + 1], opBindingStrength, true, i == e.Operators.Count - 1 && (parensNeeded || isRightmost), sem, -1, keyword);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is LetExpr) {
+ var e = (LetExpr)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("var ");
+ string sep = "";
+ foreach (var lhs in e.LHSs) {
+ wr.Write(sep);
+ PrintCasePattern(lhs);
+ sep = ", ";
+ }
+ if (e.Exact) {
+ wr.Write(" := ");
+ } else {
+ wr.Write(" :| ");
+ }
+ PrintExpressionList(e.RHSs, true);
+ wr.Write("; ");
+ PrintExpression(e.Body, !parensNeeded && isFollowedBySemicolon);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is QuantifierExpr) {
+ QuantifierExpr e = (QuantifierExpr)expr;
+
+ if (DafnyOptions.O.DafnyPrintResolvedFile != null && e.SplitQuantifier != null) {
+ PrintExpr(e.SplitQuantifierExpression, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword, resolv_count);
+ return;
+ }
+
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write(e is ForallExpr ? "forall" : "exists");
+ PrintTypeParams(e.TypeArgs); // new!
+ wr.Write(" ");
PrintQuantifierDomain(e.BoundVars, e.Attributes, e.Range);
- wr.Write(" :: ");
- if (0 <= indent) {
- int ind = indent + IndentAmount;
- wr.WriteLine();
- Indent(ind);
- PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon, ind);
- } else {
- PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
- }
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is NamedExpr) {
- var e = (NamedExpr)expr;
- wr.Write("expr {0}: ", e.Name);
- PrintExpression(e.Body, isFollowedBySemicolon);
-
- } else if (expr is SetComprehension) {
- var e = (SetComprehension)expr;
- bool parensNeeded = !isRightmost;
- if (parensNeeded) { wr.Write("("); }
- wr.Write("set ");
- string sep = "";
- foreach (BoundVar bv in e.BoundVars) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- sep = ", ";
- PrintType(": ", bv.Type);
- }
- PrintAttributes(e.Attributes);
- wr.Write(" | ");
- PrintExpression(e.Range, !parensNeeded && isFollowedBySemicolon);
- if (!e.TermIsImplicit) {
- wr.Write(" :: ");
- PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
- }
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is MapComprehension) {
- var e = (MapComprehension)expr;
- bool parensNeeded = !isRightmost;
- if (parensNeeded) { wr.Write("("); }
- wr.Write(e.Finite ? "map " : "imap ");
- string sep = "";
- foreach (BoundVar bv in e.BoundVars) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- sep = ", ";
- PrintType(": ", bv.Type);
- }
- PrintAttributes(e.Attributes);
- wr.Write(" | ");
- PrintExpression(e.Range, !parensNeeded && isFollowedBySemicolon);
- wr.Write(" :: ");
- PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is LambdaExpr) {
- var e = (LambdaExpr)expr;
- wr.Write("(");
- wr.Write(Util.Comma(e.BoundVars, bv => bv.DisplayName + ":" + bv.Type));
- wr.Write(")");
- if (e.Range != null) {
- wr.Write(" requires ");
- PrintExpression(e.Range, false);
- }
- foreach (var read in e.Reads) {
- wr.Write(" reads ");
- PrintExpression(read.E, false);
- }
- wr.Write(e.OneShot ? " -> " : " => ");
- PrintExpression(e.Body, isFollowedBySemicolon);
-
- } else if (expr is WildcardExpr) {
- wr.Write("*");
-
- } else if (expr is StmtExpr) {
- var e = (StmtExpr)expr;
- bool parensNeeded;
- if (e.S is AssertStmt || e.S is AssumeStmt || e.S is CalcStmt) {
- parensNeeded = !isRightmost;
- } else {
- parensNeeded = !isRightmost || isFollowedBySemicolon;
- }
- if (parensNeeded) { wr.Write("("); }
- int ind = indent < 0 ? IndentAmount : indent; // if the expression was to be printed on one line, instead print the .S part at indentation IndentAmount (not pretty, but something)
- PrintStatement(e.S, ind);
- wr.Write(" ");
- PrintExpression(e.E, !parensNeeded && isFollowedBySemicolon);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is ITEExpr) {
- ITEExpr ite = (ITEExpr)expr;
- bool parensNeeded = !isRightmost;
- if (parensNeeded) { wr.Write("("); }
- wr.Write("if ");
- PrintExpression(ite.Test, false);
- wr.Write(" then ");
- PrintExpression(ite.Thn, false);
- wr.Write(" else ");
- PrintExpression(ite.Els, !parensNeeded && isFollowedBySemicolon);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is ParensExpression) {
- var e = (ParensExpression)expr;
+ string s = keyword ?? " :: ";
+ wr.Write("{0}", s);
+ if (0 <= indent) {
+ int ind = indent + IndentAmount;
+ wr.WriteLine();
+ Indent(ind);
+ PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon, ind);
+ } else {
+ PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is NamedExpr) {
+ var e = (NamedExpr)expr;
+ wr.Write("expr {0}: ", e.Name);
+ PrintExpression(e.Body, isFollowedBySemicolon);
+
+ } else if (expr is SetComprehension) {
+ var e = (SetComprehension)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("set ");
+ string sep = "";
+ foreach (BoundVar bv in e.BoundVars) {
+ wr.Write("{0}{1}", sep, bv.DisplayName);
+ sep = ", ";
+ PrintType(": ", bv.Type);
+ }
+ PrintAttributes(e.Attributes);
+ wr.Write(" | ");
+ PrintExpression(e.Range, !parensNeeded && isFollowedBySemicolon);
+ if (!e.TermIsImplicit) {
+ wr.Write(" :: ");
+ PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
+ }
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is MapComprehension) {
+ var e = (MapComprehension)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write(e.Finite ? "map " : "imap ");
+ string sep = "";
+ foreach (BoundVar bv in e.BoundVars) {
+ wr.Write("{0}{1}", sep, bv.DisplayName);
+ sep = ", ";
+ PrintType(": ", bv.Type);
+ }
+ PrintAttributes(e.Attributes);
+ wr.Write(" | ");
+ PrintExpression(e.Range, !parensNeeded && isFollowedBySemicolon);
+ wr.Write(" :: ");
+ PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is LambdaExpr) {
+ var e = (LambdaExpr)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ var skipSignatureParens = e.BoundVars.Count == 1 && e.BoundVars[0].Type is InferredTypeProxy;
+ if (!skipSignatureParens) { wr.Write("("); }
+ wr.Write(Util.Comma(", ", e.BoundVars, bv => bv.DisplayName + (bv.Type is InferredTypeProxy ? "" : ": " + bv.Type)));
+ if (!skipSignatureParens) { wr.Write(")"); }
+ if (e.Range != null) {
+ wr.Write(" requires ");
+ PrintExpression(e.Range, false);
+ }
+ foreach (var read in e.Reads) {
+ wr.Write(" reads ");
+ PrintExpression(read.E, false);
+ }
+ wr.Write(e.OneShot ? " -> " : " => ");
+ PrintExpression(e.Body, isFollowedBySemicolon);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is WildcardExpr) {
+ wr.Write("*");
+
+ } else if (expr is StmtExpr) {
+ var e = (StmtExpr)expr;
+ bool parensNeeded;
+ if (e.S is AssertStmt || e.S is AssumeStmt || e.S is CalcStmt) {
+ parensNeeded = !isRightmost;
+ } else {
+ parensNeeded = !isRightmost || isFollowedBySemicolon;
+ }
+ if (parensNeeded) { wr.Write("("); }
+ int ind = indent < 0 ? IndentAmount : indent; // if the expression was to be printed on one line, instead print the .S part at indentation IndentAmount (not pretty, but something)
+ PrintStatement(e.S, ind);
+ wr.Write(" ");
+ PrintExpression(e.E, !parensNeeded && isFollowedBySemicolon);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is ITEExpr) {
+ ITEExpr ite = (ITEExpr)expr;
+ bool parensNeeded = !isRightmost;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("if ");
+ PrintExpression(ite.Test, false);
+ wr.Write(" then ");
+ PrintExpression(ite.Thn, false);
+ wr.Write(" else ");
+ PrintExpression(ite.Els, !parensNeeded && isFollowedBySemicolon);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is ParensExpression) {
+ var e = (ParensExpression)expr;
// printing of parentheses is done optimally, not according to the parentheses in the given program
- PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent);
-
- } else if (expr is NegationExpression) {
- var e = (NegationExpression)expr;
- string op = "-";
- int opBindingStrength = 0x60;
- bool parensNeeded = opBindingStrength < contextBindingStrength ||
- (fragileContext && opBindingStrength == contextBindingStrength);
-
- bool containsNestedNegation = e.E is ParensExpression && ((ParensExpression)e.E).E is NegationExpression;
-
- if (parensNeeded) { wr.Write("("); }
+ PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);
+
+ } else if (expr is NegationExpression) {
+ var e = (NegationExpression)expr;
+ string op = "-";
+ int opBindingStrength = 0x60;
+ bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);
+
+ bool containsNestedNegation = e.E is ParensExpression && ((ParensExpression)e.E).E is NegationExpression;
+
+ if (parensNeeded) { wr.Write("("); }
wr.Write(op);
- PrintExpr(e.E, opBindingStrength, containsNestedNegation, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1);
- if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is MatchExpr) {
- var e = (MatchExpr)expr;
- var parensNeeded = !isRightmost && !e.UsesOptionalBraces;
- if (parensNeeded) { wr.Write("("); }
- wr.Write("match ");
- PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, !parensNeeded && isFollowedBySemicolon);
- if (e.UsesOptionalBraces) { wr.Write(" {"); }
- int i = 0;
- foreach (var mc in e.Cases) {
- bool isLastCase = i == e.Cases.Count - 1;
- wr.Write(" case {0}", mc.Id);
- if (mc.Arguments.Count != 0) {
- string sep = "(";
- foreach (BoundVar bv in mc.Arguments) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- sep = ", ";
- }
- wr.Write(")");
- }
- wr.Write(" => ");
- PrintExpression(mc.Body, isRightmost && isLastCase, !parensNeeded && isFollowedBySemicolon);
- i++;
- }
- if (e.UsesOptionalBraces) { wr.Write(" }"); }
- else if (parensNeeded) { wr.Write(")"); }
-
- } else if (expr is BoxingCastExpr) {
- // this is not expected for a parsed program, but we may be called for /trace purposes in the translator
+ PrintExpr(e.E, opBindingStrength, containsNestedNegation, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1, keyword);
+ if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is MatchExpr) {
+ var e = (MatchExpr)expr;
+ var parensNeeded = !isRightmost && !e.UsesOptionalBraces;
+ if (parensNeeded) { wr.Write("("); }
+ wr.Write("match ");
+ PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, !parensNeeded && isFollowedBySemicolon);
+ if (e.UsesOptionalBraces) { wr.Write(" {"); }
+ int i = 0;
+ foreach (var mc in e.Cases) {
+ bool isLastCase = i == e.Cases.Count - 1;
+ wr.Write(" case {0}", mc.Id);
+ PrintMatchCaseArgument(mc);
+ wr.Write(" => ");
+ PrintExpression(mc.Body, isRightmost && isLastCase, !parensNeeded && isFollowedBySemicolon);
+ i++;
+ }
+ if (e.UsesOptionalBraces) { wr.Write(" }"); }
+ else if (parensNeeded) { wr.Write(")"); }
+
+ } else if (expr is BoxingCastExpr) {
+ // this is not expected for a parsed program, but we may be called for /trace purposes in the translator
var e = (BoxingCastExpr)expr;
- PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent);
- } else if (expr is Translator.BoogieWrapper) {
+ PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);
+ } else if (expr is Translator.BoogieWrapper) {
wr.Write("[BoogieWrapper]"); // this is somewhat unexpected, but we can get here if the /trace switch is used, so it seems best to cover this case here
+ } else if (expr is Translator.BoogieFunctionCall) {
+ wr.Write("[BoogieFunctionCall]"); // this prevents debugger watch window crash
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
- }
- }
-
- bool ParensMayMatter(Expression expr) {
- Contract.Requires(expr != null);
- int parenPairs = 0;
- for (; expr is ParensExpression; parenPairs++) {
- expr = ((ParensExpression)expr).E;
- }
- // If the program were resolved, we could be more precise than the following (in particular, looking
- // to see if expr denotes a MemberSelectExpr of a member that is a Function.
- return parenPairs != 0 && (expr is NameSegment || expr is ExprDotName);
- }
-
- void PrintCasePattern(CasePattern pat) {
- Contract.Requires(pat != null);
- var v = pat.Var;
- if (v != null) {
- wr.Write(v.DisplayName);
- if (v.Type is NonProxyType || DafnyOptions.O.DafnyPrintResolvedFile != null) {
- PrintType(": ", v.Type);
- }
- } else {
- wr.Write(pat.Id);
- if (pat.Arguments != null) {
- wr.Write("(");
- var sep = "";
- foreach (var arg in pat.Arguments) {
- wr.Write(sep);
- PrintCasePattern(arg);
- sep = ", ";
- }
- wr.Write(")");
- }
- }
- }
-
- private void PrintQuantifierDomain(List<BoundVar> boundVars, Attributes attrs, Expression range) {
- Contract.Requires(boundVars != null);
- string sep = "";
- foreach (BoundVar bv in boundVars) {
- wr.Write("{0}{1}", sep, bv.DisplayName);
- PrintType(": ", bv.Type);
- sep = ", ";
- }
- PrintAttributes(attrs);
- if (range != null) {
- wr.Write(" | ");
- PrintExpression(range, false);
- }
- }
-
- void PrintActualArguments(List<Expression> args, string name) {
- Contract.Requires(args != null);
- Contract.Requires(name != null);
- if (name.EndsWith("#")) {
- wr.Write("[");
- PrintExpression(args[0], false);
- wr.Write("]");
- args = new List<Expression>(args.Skip(1));
- }
- wr.Write("(");
- PrintExpressionList(args, false);
- wr.Write(")");
- }
-
- void PrintExpressionList(List<Expression> exprs, bool isFollowedBySemicolon) {
- Contract.Requires(exprs != null);
- string sep = "";
- foreach (Expression e in exprs) {
- Contract.Assert(e != null);
- wr.Write(sep);
- sep = ", ";
- PrintExpression(e, isFollowedBySemicolon);
- }
- }
- void PrintExpressionPairList(List<ExpressionPair> exprs) {
- Contract.Requires(exprs != null);
- string sep = "";
- foreach (ExpressionPair p in exprs) {
- Contract.Assert(p != null);
- wr.Write(sep);
- sep = ", ";
- PrintExpression(p.A, false);
- wr.Write(":=");
- PrintExpression(p.B, false);
- }
- }
-
- void PrintFrameExpressionList(List<FrameExpression/*!*/>/*!*/ fexprs) {
- Contract.Requires(fexprs != null);
- string sep = "";
- foreach (FrameExpression fe in fexprs) {
- Contract.Assert(fe != null);
- wr.Write(sep);
- sep = ", ";
- PrintExpression(fe.E, true);
- if (fe.FieldName != null) {
- wr.Write("`{0}", fe.FieldName);
- }
- }
- }
- }
-}
+ }
+ }
+
+ bool ParensMayMatter(Expression expr) {
+ Contract.Requires(expr != null);
+ int parenPairs = 0;
+ for (; expr is ParensExpression; parenPairs++) {
+ expr = ((ParensExpression)expr).E;
+ }
+ // If the program were resolved, we could be more precise than the following (in particular, looking
+ // to see if expr denotes a MemberSelectExpr of a member that is a Function.
+ return parenPairs != 0 && (expr is NameSegment || expr is ExprDotName);
+ }
+
+ void PrintCasePattern(CasePattern pat) {
+ Contract.Requires(pat != null);
+ var v = pat.Var;
+ if (v != null) {
+ wr.Write(v.DisplayName);
+ if (v.Type is NonProxyType || DafnyOptions.O.DafnyPrintResolvedFile != null) {
+ PrintType(": ", v.Type);
+ }
+ } else {
+ wr.Write(pat.Id);
+ if (pat.Arguments != null) {
+ wr.Write("(");
+ var sep = "";
+ foreach (var arg in pat.Arguments) {
+ wr.Write(sep);
+ PrintCasePattern(arg);
+ sep = ", ";
+ }
+ wr.Write(")");
+ }
+ }
+ }
+
+ private void PrintQuantifierDomain(List<BoundVar> boundVars, Attributes attrs, Expression range) {
+ Contract.Requires(boundVars != null);
+ string sep = "";
+ foreach (BoundVar bv in boundVars) {
+ wr.Write("{0}{1}", sep, bv.DisplayName);
+ PrintType(": ", bv.Type);
+ sep = ", ";
+ }
+ PrintAttributes(attrs);
+ if (range != null) {
+ wr.Write(" | ");
+ PrintExpression(range, false);
+ }
+ }
+
+ void PrintActualArguments(List<Expression> args, string name) {
+ Contract.Requires(args != null);
+ Contract.Requires(name != null);
+ if (name.EndsWith("#")) {
+ wr.Write("[");
+ PrintExpression(args[0], false);
+ wr.Write("]");
+ args = new List<Expression>(args.Skip(1));
+ }
+ wr.Write("(");
+ PrintExpressionList(args, false);
+ wr.Write(")");
+ }
+
+ void PrintExpressionList(List<Expression> exprs, bool isFollowedBySemicolon) {
+ Contract.Requires(exprs != null);
+ string sep = "";
+ foreach (Expression e in exprs) {
+ Contract.Assert(e != null);
+ wr.Write(sep);
+ sep = ", ";
+ PrintExpression(e, isFollowedBySemicolon);
+ }
+ }
+ void PrintExpressionPairList(List<ExpressionPair> exprs) {
+ Contract.Requires(exprs != null);
+ string sep = "";
+ foreach (ExpressionPair p in exprs) {
+ Contract.Assert(p != null);
+ wr.Write(sep);
+ sep = ", ";
+ PrintExpression(p.A, false);
+ wr.Write(":=");
+ PrintExpression(p.B, false);
+ }
+ }
+
+ void PrintFrameExpressionList(List<FrameExpression/*!*/>/*!*/ fexprs) {
+ Contract.Requires(fexprs != null);
+ string sep = "";
+ foreach (FrameExpression fe in fexprs) {
+ Contract.Assert(fe != null);
+ wr.Write(sep);
+ sep = ", ";
+ PrintExpression(fe.E, true);
+ if (fe.FieldName != null) {
+ wr.Write("`{0}", fe.FieldName);
+ }
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs
index d819652d..a243ad53 100644
--- a/Source/Dafny/RefinementTransformer.cs
+++ b/Source/Dafny/RefinementTransformer.cs
@@ -52,16 +52,19 @@ namespace Microsoft.Dafny
public class RefinementTransformer : IRewriter
{
- ResolutionErrorReporter reporter;
- Action<AdditionalInformation> additionalInformationReporter;
Cloner rawCloner; // This cloner just gives exactly the same thing back.
RefinementCloner refinementCloner; // This cloner wraps things in a RefinementTransformer
+
Program program;
- public RefinementTransformer(ResolutionErrorReporter reporter, Action<AdditionalInformation> additionalInformationReporter, Program p) {
- Contract.Requires(reporter != null);
- this.reporter = reporter;
- this.additionalInformationReporter = additionalInformationReporter;
+
+ public RefinementTransformer(ErrorReporter reporter)
+ : base(reporter) {
rawCloner = new Cloner();
+ }
+
+ public RefinementTransformer(Program p)
+ : this(p.reporter) {
+ Contract.Requires(p != null);
program = p;
}
@@ -71,27 +74,47 @@ namespace Microsoft.Dafny
private Method currentMethod;
public ModuleSignature RefinedSig; // the intention is to use this field only after a successful PreResolve
- void ReportAdditionalInformation(IToken token, string text, int length)
- {
- Contract.Requires(token != null);
- Contract.Requires(text != null);
- Contract.Requires(0 <= length);
- if (additionalInformationReporter != null) {
- additionalInformationReporter(new AdditionalInformation { Token = token, Text = text, Length = length });
- }
- }
-
- public void PreResolve(ModuleDefinition m) {
+ internal override void PreResolve(ModuleDefinition m) {
if (m.RefinementBaseRoot != null) {
if (Resolver.ResolvePath(m.RefinementBaseRoot, m.RefinementBaseName, out RefinedSig, reporter)) {
if (RefinedSig.ModuleDef != null) {
m.RefinementBase = RefinedSig.ModuleDef;
+ if (m.IsExclusiveRefinement) {
+ if (null == m.RefinementBase.ExclusiveRefinement) {
+ m.RefinementBase.ExclusiveRefinement = m;
+ } else {
+ reporter.Error(MessageSource.RefinementTransformer,
+ m.tok,
+ "no more than one exclusive refinement may exist for a given module.");
+ }
+ }
+ // check that the openess in the imports between refinement and its base matches
+ List<TopLevelDecl> declarations = m.TopLevelDecls;
+ List<TopLevelDecl> baseDeclarations = m.RefinementBase.TopLevelDecls;
+ foreach (var im in declarations) {
+ if (im is ModuleDecl) {
+ ModuleDecl mdecl = (ModuleDecl)im;
+ //find the matching import from the base
+ foreach (var bim in baseDeclarations) {
+ if (bim is ModuleDecl && ((ModuleDecl)bim).Name.Equals(mdecl.Name)) {
+ if (mdecl.Opened != ((ModuleDecl)bim).Opened) {
+ string message = mdecl.Opened ?
+ "{0} in {1} cannot be imported with \"opened\" because it does not match the corresponding import in the refinement base {2} " :
+ "{0} in {1} must be imported with \"opened\" to match the corresponding import in its refinement base {2}.";
+ reporter.Error(MessageSource.RefinementTransformer,m.tok, message, im.Name, m.Name, m.RefinementBase.Name);
+ }
+ break;
+ }
+ }
+ }
+ }
+
PreResolveWorker(m);
} else {
- reporter.Error(m.RefinementBaseName[0], "module ({0}) named as refinement base is not a literal module or simple reference to a literal module", Util.Comma(".", m.RefinementBaseName, x => x.val));
+ reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName[0], "module ({0}) named as refinement base is not a literal module or simple reference to a literal module", Util.Comma(".", m.RefinementBaseName, x => x.val));
}
} else {
- reporter.Error(m.RefinementBaseName[0], "module ({0}) named as refinement base does not exist", Util.Comma(".", m.RefinementBaseName, x => x.val));
+ reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName[0], "module ({0}) named as refinement base does not exist", Util.Comma(".", m.RefinementBaseName, x => x.val));
}
}
}
@@ -118,99 +141,117 @@ namespace Microsoft.Dafny
}
// Merge the declarations of prev into the declarations of m
+ List<string> processedDecl = new List<string>();
foreach (var d in prev.TopLevelDecls) {
int index;
+ processedDecl.Add(d.Name);
if (!declaredNames.TryGetValue(d.Name, out index)) {
m.TopLevelDecls.Add(refinementCloner.CloneDeclaration(d, m));
} else {
var nw = m.TopLevelDecls[index];
- if (d is ModuleDecl) {
- if (!(nw is ModuleDecl)) {
- reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
- } else if (!(d is ModuleFacadeDecl)) {
- reporter.Error(nw, "a module ({0}) can only refine a module facade", nw.Name);
- } else {
- ModuleSignature original = ((ModuleFacadeDecl)d).OriginalSignature;
- ModuleSignature derived = null;
- if (nw is AliasModuleDecl) {
- derived = ((AliasModuleDecl)nw).Signature;
- } else if (nw is ModuleFacadeDecl) {
- derived = ((ModuleFacadeDecl)nw).Signature;
- } else {
- reporter.Error(nw, "a module ({0}) can only be refined by an alias module or a module facade", d.Name);
+ MergeTopLevelDecls(m, nw, d, index);
+ }
+ }
+
+ // Merge the imports of prev
+ var prevTopLevelDecls = RefinedSig.TopLevels.Values;
+ foreach (var d in prevTopLevelDecls) {
+ int index;
+ if (!processedDecl.Contains(d.Name) && (declaredNames.TryGetValue(d.Name, out index))) {
+ // if it is redefined, we need to merge them.
+ var nw = m.TopLevelDecls[index];
+ MergeTopLevelDecls(m, nw, d, index);
+ }
+ }
+ m.RefinementBaseSig = RefinedSig;
+
+ Contract.Assert(moduleUnderConstruction == m); // this should be as it was set earlier in this method
+ }
+
+ private void MergeTopLevelDecls(ModuleDefinition m, TopLevelDecl nw, TopLevelDecl d, int index) {
+ if (d is ModuleDecl) {
+ if (!(nw is ModuleDecl)) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
+ } else if (!(d is ModuleFacadeDecl)) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) can only refine a module facade", nw.Name);
+ } else {
+ ModuleSignature original = ((ModuleFacadeDecl)d).OriginalSignature;
+ ModuleSignature derived = null;
+ if (nw is AliasModuleDecl) {
+ derived = ((AliasModuleDecl)nw).Signature;
+ } else if (nw is ModuleFacadeDecl) {
+ derived = ((ModuleFacadeDecl)nw).Signature;
+ } else {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) can only be refined by an alias module or a module facade", d.Name);
+ }
+ if (derived != null) {
+ // check that the new module refines the previous declaration
+ if (!CheckIsRefinement(derived, original))
+ reporter.Error(MessageSource.RefinementTransformer, nw.tok, "a module ({0}) can only be replaced by a refinement of the original module", d.Name);
+ }
+ }
+ } else if (d is OpaqueTypeDecl) {
+ if (nw is ModuleDecl) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
+ } else {
+ bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality;
+ if (nw is OpaqueTypeDecl) {
+ if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
+ }
+ if (nw.TypeArgs.Count != d.TypeArgs.Count) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "type '{0}' is not allowed to change its number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
+ }
+ } else if (dDemandsEqualitySupport) {
+ if (nw is ClassDecl) {
+ // fine, as long as "nw" takes the right number of type parameters
+ if (nw.TypeArgs.Count != d.TypeArgs.Count) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a class that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
}
- if (derived != null) {
- // check that the new module refines the previous declaration
- if (!CheckIsRefinement(derived, original))
- reporter.Error(nw.tok, "a module ({0}) can only be replaced by a refinement of the original module", d.Name);
+ } else if (nw is NewtypeDecl) {
+ // fine, as long as "nw" does not take any type parameters
+ if (nw.TypeArgs.Count != 0) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}', which has {1} type argument{2}, is not allowed to be replaced by a newtype, which takes none", nw.Name, d.TypeArgs.Count, d.TypeArgs.Count == 1 ? "" : "s");
}
- }
- } else if (d is OpaqueTypeDecl) {
- if (nw is ModuleDecl) {
- reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
+ } else if (nw is CoDatatypeDecl) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
} else {
- bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality;
- if (nw is OpaqueTypeDecl) {
- if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) {
- reporter.Error(nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
- }
- if (nw.TypeArgs.Count != d.TypeArgs.Count) {
- reporter.Error(nw, "type '{0}' is not allowed to change its number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
- }
- } else if (dDemandsEqualitySupport) {
- if (nw is ClassDecl) {
- // fine, as long as "nw" takes the right number of type parameters
- if (nw.TypeArgs.Count != d.TypeArgs.Count) {
- reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a class that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
- }
- } else if (nw is NewtypeDecl) {
- // fine, as long as "nw" does not take any type parameters
- if (nw.TypeArgs.Count != 0) {
- reporter.Error(nw, "opaque type '{0}', which has {1} type argument{2}, is not allowed to be replaced by a newtype, which takes none", nw.Name, d.TypeArgs.Count, d.TypeArgs.Count == 1 ? "" : "s");
- }
- } else if (nw is CoDatatypeDecl) {
- reporter.Error(nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
- } else {
- Contract.Assert(nw is IndDatatypeDecl || nw is TypeSynonymDecl);
- if (nw.TypeArgs.Count != d.TypeArgs.Count) {
- reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
- } else {
- // Here, we need to figure out if the new type supports equality. But we won't know about that until resolution has
- // taken place, so we defer it until the PostResolve phase.
- var udt = UserDefinedType.FromTopLevelDecl(nw.tok, nw);
- postTasks.Enqueue(() => {
- if (!udt.SupportsEquality) {
- reporter.Error(udt.tok, "type '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", udt.Name);
- }
- });
+ Contract.Assert(nw is IndDatatypeDecl || nw is TypeSynonymDecl);
+ if (nw.TypeArgs.Count != d.TypeArgs.Count) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
+ } else {
+ // Here, we need to figure out if the new type supports equality. But we won't know about that until resolution has
+ // taken place, so we defer it until the PostResolve phase.
+ var udt = UserDefinedType.FromTopLevelDecl(nw.tok, nw);
+ postTasks.Enqueue(() => {
+ if (!udt.SupportsEquality) {
+ reporter.Error(MessageSource.RefinementTransformer, udt.tok, "type '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", udt.Name);
}
- }
- } else if (d.TypeArgs.Count != nw.TypeArgs.Count) {
- reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
+ });
}
}
- } else if (nw is OpaqueTypeDecl) {
- reporter.Error(nw, "an opaque type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base", nw.Name);
- } else if (nw is DatatypeDecl) {
- reporter.Error(nw, "a datatype declaration ({0}) in a refinement module can only replace an opaque type declaration", nw.Name);
- } else if (nw is IteratorDecl) {
- if (d is IteratorDecl) {
- m.TopLevelDecls[index] = MergeIterator((IteratorDecl)nw, (IteratorDecl)d);
- } else {
- reporter.Error(nw, "an iterator declaration ({0}) is a refining module cannot replace a different kind of declaration in the refinement base", nw.Name);
- }
- } else {
- Contract.Assert(nw is ClassDecl);
- if (d is DatatypeDecl) {
- reporter.Error(nw, "a class declaration ({0}) in a refining module cannot replace a different kind of declaration in the refinement base", nw.Name);
- } else {
- m.TopLevelDecls[index] = MergeClass((ClassDecl)nw, (ClassDecl)d);
- }
+ } else if (d.TypeArgs.Count != nw.TypeArgs.Count) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count);
}
}
+ } else if (nw is OpaqueTypeDecl) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "an opaque type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base", nw.Name);
+ } else if (nw is DatatypeDecl) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a datatype declaration ({0}) in a refinement module can only replace an opaque type declaration", nw.Name);
+ } else if (nw is IteratorDecl) {
+ if (d is IteratorDecl) {
+ m.TopLevelDecls[index] = MergeIterator((IteratorDecl)nw, (IteratorDecl)d);
+ } else {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "an iterator declaration ({0}) is a refining module cannot replace a different kind of declaration in the refinement base", nw.Name);
+ }
+ } else {
+ Contract.Assert(nw is ClassDecl);
+ if (d is DatatypeDecl) {
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a class declaration ({0}) in a refining module cannot replace a different kind of declaration in the refinement base", nw.Name);
+ } else {
+ m.TopLevelDecls[index] = MergeClass((ClassDecl)nw, (ClassDecl)d);
+ }
}
-
- Contract.Assert(moduleUnderConstruction == m); // this should be as it was set earlier in this method
}
public bool CheckIsRefinement(ModuleSignature derived, ModuleSignature original) {
@@ -229,42 +270,42 @@ namespace Microsoft.Dafny
// Second, we need to determine whether the specifications will be compatible
// (i.e. substitutable), by translating to Boogie.
- var errorCount = reporter.ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
foreach (var kv in original.TopLevels) {
var d = kv.Value;
TopLevelDecl nw;
if (derived.TopLevels.TryGetValue(kv.Key, out nw)) {
if (d is ModuleDecl) {
if (!(nw is ModuleDecl)) {
- reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
} else {
CheckIsRefinement(((ModuleDecl)nw).Signature, ((ModuleDecl)d).Signature);
}
} else if (d is OpaqueTypeDecl) {
if (nw is ModuleDecl) {
- reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
} else {
bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality;
if (nw is OpaqueTypeDecl) {
if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) {
- reporter.Error(nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
}
} else if (dDemandsEqualitySupport) {
if (nw is ClassDecl) {
// fine, as long as "nw" does not take any type parameters
if (nw.TypeArgs.Count != 0) {
- reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name);
}
} else if (nw is CoDatatypeDecl) {
- reporter.Error(nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
} else {
Contract.Assert(nw is IndDatatypeDecl);
if (nw.TypeArgs.Count != 0) {
- reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name);
} else {
var udt = new UserDefinedType(nw.tok, nw.Name, nw, new List<Type>());
if (!(udt.SupportsEquality)) {
- reporter.Error(nw.tok, "datatype '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw.tok, "datatype '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", nw.Name);
}
}
}
@@ -273,18 +314,18 @@ namespace Microsoft.Dafny
} else if (d is DatatypeDecl) {
if (nw is DatatypeDecl) {
if (d is IndDatatypeDecl && !(nw is IndDatatypeDecl)) {
- reporter.Error(nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name);
} else if (d is CoDatatypeDecl && !(nw is CoDatatypeDecl)) {
- reporter.Error(nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name);
}
// check constructors, formals, etc.
CheckDatatypesAreRefinements((DatatypeDecl)d, (DatatypeDecl)nw);
} else {
- reporter.Error(nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name);
}
} else if (d is ClassDecl) {
if (!(nw is ClassDecl)) {
- reporter.Error(nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name);
} else {
CheckClassesAreRefinements((ClassDecl)nw, (ClassDecl)d);
}
@@ -292,15 +333,15 @@ namespace Microsoft.Dafny
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected toplevel
}
} else {
- reporter.Error(d, "declaration {0} must have a matching declaration in the refining module", d.Name);
+ reporter.Error(MessageSource.RefinementTransformer, d, "declaration {0} must have a matching declaration in the refining module", d.Name);
}
}
- return errorCount == reporter.ErrorCount;
+ return errorCount == reporter.Count(ErrorLevel.Error);
}
private void CheckClassesAreRefinements(ClassDecl nw, ClassDecl d) {
if (nw.TypeArgs.Count != d.TypeArgs.Count) {
- reporter.Error(nw, "a refining class ({0}) must have the same number of type parameters", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a refining class ({0}) must have the same number of type parameters", nw.Name);
} else {
var map = new Dictionary<string, MemberDecl>();
foreach (var mem in nw.Members) {
@@ -310,33 +351,33 @@ namespace Microsoft.Dafny
MemberDecl newMem;
if (map.TryGetValue(m.Name, out newMem)) {
if (m.HasStaticKeyword != newMem.HasStaticKeyword) {
- reporter.Error(newMem, "member {0} must {1}", m.Name, m.HasStaticKeyword ? "be static" : "not be static");
+ reporter.Error(MessageSource.RefinementTransformer, newMem, "member {0} must {1}", m.Name, m.HasStaticKeyword ? "be static" : "not be static");
}
if (m is Field) {
if (newMem is Field) {
var newField = (Field)newMem;
if (!ResolvedTypesAreTheSame(newField.Type, ((Field)m).Type))
- reporter.Error(newMem, "field must be refined by a field with the same type (got {0}, expected {1})", newField.Type, ((Field)m).Type);
+ reporter.Error(MessageSource.RefinementTransformer, newMem, "field must be refined by a field with the same type (got {0}, expected {1})", newField.Type, ((Field)m).Type);
if (m.IsGhost || !newField.IsGhost)
- reporter.Error(newField, "a field re-declaration ({0}) must be to ghostify the field", newField.Name, nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, newField, "a field re-declaration ({0}) must be to ghostify the field", newField.Name, nw.Name);
} else {
- reporter.Error(newMem, "a field declaration ({1}) must be replaced by a field in the refinement base (not {0})", newMem.Name, nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, newMem, "a field declaration ({1}) must be replaced by a field in the refinement base (not {0})", newMem.Name, nw.Name);
}
} else if (m is Method) {
if (newMem is Method) {
CheckMethodsAreRefinements((Method)newMem, (Method)m);
} else {
- reporter.Error(newMem, "method must be refined by a method");
+ reporter.Error(MessageSource.RefinementTransformer, newMem, "method must be refined by a method");
}
} else if (m is Function) {
if (newMem is Function) {
CheckFunctionsAreRefinements((Function)newMem, (Function)m);
} else {
- reporter.Error(newMem, "{0} must be refined by a {0}", m.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, newMem, "{0} must be refined by a {0}", m.WhatKind);
}
}
} else {
- reporter.Error(nw is DefaultClassDecl ? nw.Module.tok : nw.tok, "refining {0} must have member {1}", nw is DefaultClassDecl ? "module" : "class", m.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw is DefaultClassDecl ? nw.Module.tok : nw.tok, "refining {0} must have member {1}", nw is DefaultClassDecl ? "module" : "class", m.Name);
}
}
}
@@ -349,17 +390,17 @@ namespace Microsoft.Dafny
Contract.Requires(thing != null);
Contract.Requires(parameterKind != null);
if (old.Count != nw.Count) {
- reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
+ reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
} else {
for (int i = 0; i < old.Count; i++) {
var o = old[i];
var n = nw[i];
if (!o.IsGhost && n.IsGhost) {
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
} else if (o.IsGhost && !n.IsGhost) {
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
} else if (!ResolvedTypesAreTheSame(o.Type, n.Type)) {
- reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
}
}
}
@@ -373,22 +414,22 @@ namespace Microsoft.Dafny
private void CheckFunctionsAreRefinements(Function nw, Function f) {
if (f is Predicate) {
if (!(nw is Predicate)) {
- reporter.Error(nw, "a predicate declaration ({0}) can only be refined by a predicate", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a predicate declaration ({0}) can only be refined by a predicate", nw.Name);
} else {
CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "predicate", false);
CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "predicate", "parameter");
}
} else if (f is FixpointPredicate) {
- reporter.Error(nw, "refinement of {0}s is not supported", f.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "refinement of {0}s is not supported", f.WhatKind);
} else {
// f is a plain Function
if (nw is Predicate || nw is FixpointPredicate) {
- reporter.Error(nw, "a {0} declaration ({1}) can only be refined by a function or function method", nw.IsGhost ? "function" : "function method", nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "a {0} declaration ({1}) can only be refined by a function or function method", nw.IsGhost ? "function" : "function method", nw.Name);
} else {
CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "function", false);
CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "function", "parameter");
if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType)) {
- reporter.Error(nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", nw.Name, nw.ResultType, f.ResultType);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", nw.Name, nw.ResultType, f.ResultType);
}
}
}
@@ -399,7 +440,7 @@ namespace Microsoft.Dafny
private void CheckDatatypesAreRefinements(DatatypeDecl dd, DatatypeDecl nn) {
CheckAgreement_TypeParameters(nn.tok, dd.TypeArgs, nn.TypeArgs, dd.Name, "datatype", false);
if (dd.Ctors.Count != nn.Ctors.Count) {
- reporter.Error(nn.tok, "a refining datatype must have the same number of constructors");
+ reporter.Error(MessageSource.RefinementTransformer, nn.tok, "a refining datatype must have the same number of constructors");
} else {
var map = new Dictionary<string, DatatypeCtor>();
foreach (var ctor in nn.Ctors) {
@@ -409,21 +450,21 @@ namespace Microsoft.Dafny
DatatypeCtor newCtor;
if (map.TryGetValue(ctor.Name, out newCtor)) {
if (newCtor.Formals.Count != ctor.Formals.Count) {
- reporter.Error(newCtor, "the constructor ({0}) must have the same number of formals as in the refined module", newCtor.Name);
+ reporter.Error(MessageSource.RefinementTransformer, newCtor, "the constructor ({0}) must have the same number of formals as in the refined module", newCtor.Name);
} else {
for (int i = 0; i < newCtor.Formals.Count; i++) {
var a = ctor.Formals[i]; var b = newCtor.Formals[i];
if (a.HasName) {
if (!b.HasName || a.Name != b.Name)
- reporter.Error(b, "formal argument {0} in constructor {1} does not have the same name as in the refined module (should be {2})", i, ctor.Name, a.Name);
+ reporter.Error(MessageSource.RefinementTransformer, b, "formal argument {0} in constructor {1} does not have the same name as in the refined module (should be {2})", i, ctor.Name, a.Name);
}
if (!ResolvedTypesAreTheSame(a.Type, b.Type)) {
- reporter.Error(b, "formal argument {0} in constructor {1} does not have the same type as in the refined module (should be {2}, not {3})", i, ctor.Name, a.Type.ToString(), b.Type.ToString());
+ reporter.Error(MessageSource.RefinementTransformer, b, "formal argument {0} in constructor {1} does not have the same type as in the refined module (should be {2}, not {3})", i, ctor.Name, a.Type.ToString(), b.Type.ToString());
}
}
}
} else {
- reporter.Error(nn, "the constructor {0} must be present in the refining datatype", ctor.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nn, "the constructor {0} must be present in the refining datatype", ctor.Name);
}
}
}
@@ -452,7 +493,8 @@ namespace Microsoft.Dafny
} else if (prev is ObjectType) {
return next is ObjectType;
} else if (prev is SetType) {
- return next is SetType && ResolvedTypesAreTheSame(((SetType)prev).Arg, ((SetType)next).Arg);
+ return next is SetType && ((SetType)prev).Finite == ((SetType)next).Finite &&
+ ResolvedTypesAreTheSame(((SetType)prev).Arg, ((SetType)next).Arg);
} else if (prev is MultiSetType) {
return next is MultiSetType && ResolvedTypesAreTheSame(((MultiSetType)prev).Arg, ((MultiSetType)next).Arg);
} else if (prev is MapType) {
@@ -491,7 +533,8 @@ namespace Microsoft.Dafny
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
}
}
- public void PostResolve(ModuleDefinition m) {
+
+ internal override void PostResolve(ModuleDefinition m) {
if (m == moduleUnderConstruction) {
while (this.postTasks.Count != 0) {
var a = postTasks.Dequeue();
@@ -502,8 +545,7 @@ namespace Microsoft.Dafny
}
moduleUnderConstruction = null;
}
- public void PostCyclicityResolve(ModuleDefinition m) {
- }
+
Function CloneFunction(IToken tok, Function f, bool isGhost, List<Expression> moreEnsures, Expression moreBody, Expression replacementBody, bool checkPrevPostconditions, Attributes moreAttributes) {
Contract.Requires(tok != null);
Contract.Requires(moreBody == null || f is Predicate);
@@ -544,16 +586,16 @@ namespace Microsoft.Dafny
if (f is Predicate) {
return new Predicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals,
- req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);
+ req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f);
} else if (f is InductivePredicate) {
return new InductivePredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, tps, formals,
- req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);
+ req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f);
} else if (f is CoPredicate) {
return new CoPredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, tps, formals,
- req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);
+ req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f);
} else {
return new Function(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals, refinementCloner.CloneType(f.ResultType),
- req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);
+ req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f);
}
}
@@ -578,19 +620,19 @@ namespace Microsoft.Dafny
var body = newBody ?? refinementCloner.CloneBlockStmt(m.Body);
if (m is Constructor) {
return new Constructor(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, tps, ins,
- req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m);
} else if (m is InductiveLemma) {
return new InductiveLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),
- req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m);
} else if (m is CoLemma) {
return new CoLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),
- req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m);
} else if (m is Lemma) {
return new Lemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),
- req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m);
} else {
return new Method(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),
- req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m);
}
}
@@ -601,26 +643,26 @@ namespace Microsoft.Dafny
Contract.Requires(prev != null);
if (nw.Requires.Count != 0) {
- reporter.Error(nw.Requires[0].E.tok, "a refining iterator is not allowed to add preconditions");
+ reporter.Error(MessageSource.RefinementTransformer, nw.Requires[0].E.tok, "a refining iterator is not allowed to add preconditions");
}
if (nw.YieldRequires.Count != 0) {
- reporter.Error(nw.YieldRequires[0].E.tok, "a refining iterator is not allowed to add yield preconditions");
+ reporter.Error(MessageSource.RefinementTransformer, nw.YieldRequires[0].E.tok, "a refining iterator is not allowed to add yield preconditions");
}
if (nw.Reads.Expressions.Count != 0) {
- reporter.Error(nw.Reads.Expressions[0].E.tok, "a refining iterator is not allowed to extend the reads clause");
+ reporter.Error(MessageSource.RefinementTransformer, nw.Reads.Expressions[0].E.tok, "a refining iterator is not allowed to extend the reads clause");
}
if (nw.Modifies.Expressions.Count != 0) {
- reporter.Error(nw.Modifies.Expressions[0].E.tok, "a refining iterator is not allowed to extend the modifies clause");
+ reporter.Error(MessageSource.RefinementTransformer, nw.Modifies.Expressions[0].E.tok, "a refining iterator is not allowed to extend the modifies clause");
}
if (nw.Decreases.Expressions.Count != 0) {
- reporter.Error(nw.Decreases.Expressions[0].tok, "a refining iterator is not allowed to extend the decreases clause");
+ reporter.Error(MessageSource.RefinementTransformer, nw.Decreases.Expressions[0].tok, "a refining iterator is not allowed to extend the decreases clause");
}
if (nw.SignatureIsOmitted) {
Contract.Assert(nw.TypeArgs.Count == 0);
Contract.Assert(nw.Ins.Count == 0);
Contract.Assert(nw.Outs.Count == 0);
- ReportAdditionalInformation(nw.SignatureEllipsis, Printer.IteratorSignatureToString(prev), 3);
+ reporter.Info(MessageSource.RefinementTransformer, nw.SignatureEllipsis, Printer.IteratorSignatureToString(prev));
} else {
CheckAgreement_TypeParameters(nw.tok, prev.TypeArgs, nw.TypeArgs, nw.Name, "iterator");
CheckAgreement_Parameters(nw.tok, prev.Ins, nw.Ins, nw.Name, "iterator", "in-parameter");
@@ -684,9 +726,9 @@ namespace Microsoft.Dafny
if (nwMember is Field) {
if (member is Field && TypesAreSyntacticallyEqual(((Field)nwMember).Type, ((Field)member).Type)) {
if (member.IsGhost || !nwMember.IsGhost)
- reporter.Error(nwMember, "a field re-declaration ({0}) must be to ghostify the field", nwMember.Name, nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a field re-declaration ({0}) must be to ghostify the field", nwMember.Name, nw.Name);
} else {
- reporter.Error(nwMember, "a field declaration ({0}) in a refining class ({1}) must replace a field in the refinement base", nwMember.Name, nw.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a field declaration ({0}) in a refining class ({1}) must replace a field in the refinement base", nwMember.Name, nw.Name);
}
nwMember.RefinementBase = member;
@@ -699,38 +741,38 @@ namespace Microsoft.Dafny
(isPredicate && !(member is Predicate)) ||
(isIndPredicate && !(member is InductivePredicate)) ||
(isCoPredicate && !(member is CoPredicate))) {
- reporter.Error(nwMember, "a {0} declaration ({1}) can only refine a {0}", f.WhatKind, nwMember.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a {0} declaration ({1}) can only refine a {0}", f.WhatKind, nwMember.Name);
} else if (f.IsProtected != ((Function)member).IsProtected) {
- reporter.Error(f, "a {0} in a refinement module must be declared 'protected' if and only if the refined {0} is", f.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, f, "a {0} in a refinement module must be declared 'protected' if and only if the refined {0} is", f.WhatKind);
} else {
var prevFunction = (Function)member;
if (f.Req.Count != 0) {
- reporter.Error(f.Req[0].tok, "a refining {0} is not allowed to add preconditions", f.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, f.Req[0].tok, "a refining {0} is not allowed to add preconditions", f.WhatKind);
}
if (f.Reads.Count != 0) {
- reporter.Error(f.Reads[0].E.tok, "a refining {0} is not allowed to extend the reads clause", f.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, f.Reads[0].E.tok, "a refining {0} is not allowed to extend the reads clause", f.WhatKind);
}
if (f.Decreases.Expressions.Count != 0) {
- reporter.Error(f.Decreases.Expressions[0].tok, "decreases clause on refining {0} not supported", f.WhatKind);
+ reporter.Error(MessageSource.RefinementTransformer, f.Decreases.Expressions[0].tok, "decreases clause on refining {0} not supported", f.WhatKind);
}
if (prevFunction.HasStaticKeyword != f.HasStaticKeyword) {
- reporter.Error(f, "a function in a refining module cannot be changed from static to non-static or vice versa: {0}", f.Name);
+ reporter.Error(MessageSource.RefinementTransformer, f, "a function in a refining module cannot be changed from static to non-static or vice versa: {0}", f.Name);
}
if (!prevFunction.IsGhost && f.IsGhost) {
- reporter.Error(f, "a function method cannot be changed into a (ghost) function in a refining module: {0}", f.Name);
+ reporter.Error(MessageSource.RefinementTransformer, f, "a function method cannot be changed into a (ghost) function in a refining module: {0}", f.Name);
} else if (prevFunction.IsGhost && !f.IsGhost && prevFunction.Body != null) {
- reporter.Error(f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name);
+ reporter.Error(MessageSource.RefinementTransformer, f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name);
}
if (f.SignatureIsOmitted) {
Contract.Assert(f.TypeArgs.Count == 0);
Contract.Assert(f.Formals.Count == 0);
- ReportAdditionalInformation(f.SignatureEllipsis, Printer.FunctionSignatureToString(prevFunction), 3);
+ reporter.Info(MessageSource.RefinementTransformer, f.SignatureEllipsis, Printer.FunctionSignatureToString(prevFunction));
} else {
CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function");
CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter");
if (!TypesAreSyntacticallyEqual(prevFunction.ResultType, f.ResultType)) {
- reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
+ reporter.Error(MessageSource.RefinementTransformer, f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
}
}
@@ -742,9 +784,9 @@ namespace Microsoft.Dafny
if (isPredicate && f.IsProtected) {
moreBody = f.Body;
} else if (isPredicate) {
- reporter.Error(nwMember, "a refining predicate is not allowed to extend/change the body unless it is declared 'protected'");
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a refining predicate is not allowed to extend/change the body unless it is declared 'protected'");
} else {
- reporter.Error(nwMember, "a refining function is not allowed to extend/change the body");
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a refining function is not allowed to extend/change the body");
}
}
var newF = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, moreBody, replacementBody, prevFunction.Body == null, f.Attributes);
@@ -755,14 +797,14 @@ namespace Microsoft.Dafny
} else {
var m = (Method)nwMember;
if (!(member is Method)) {
- reporter.Error(nwMember, "a method declaration ({0}) can only refine a method", nwMember.Name);
+ reporter.Error(MessageSource.RefinementTransformer, nwMember, "a method declaration ({0}) can only refine a method", nwMember.Name);
} else {
var prevMethod = (Method)member;
if (m.Req.Count != 0) {
- reporter.Error(m.Req[0].E.tok, "a refining method is not allowed to add preconditions");
+ reporter.Error(MessageSource.RefinementTransformer, m.Req[0].E.tok, "a refining method is not allowed to add preconditions");
}
if (m.Mod.Expressions.Count != 0) {
- reporter.Error(m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause");
+ reporter.Error(MessageSource.RefinementTransformer, m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause");
}
// If the previous method was not specified with "decreases *", then the new method is not allowed to provide any "decreases" clause.
// Any "decreases *" clause is not inherited, so if the previous method was specified with "decreases *", then the new method needs
@@ -775,23 +817,23 @@ namespace Microsoft.Dafny
} else {
if (!Contract.Exists(prevMethod.Decreases.Expressions, e => e is WildcardExpr)) {
// If the previous loop was not specified with "decreases *", then the new loop is not allowed to provide any "decreases" clause.
- reporter.Error(m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'");
+ reporter.Error(MessageSource.RefinementTransformer, m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'");
}
decreases = m.Decreases;
}
if (prevMethod.HasStaticKeyword != m.HasStaticKeyword) {
- reporter.Error(m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name);
+ reporter.Error(MessageSource.RefinementTransformer, m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name);
}
if (prevMethod.IsGhost && !m.IsGhost) {
- reporter.Error(m, "a method cannot be changed into a ghost method in a refining module: {0}", m.Name);
+ reporter.Error(MessageSource.RefinementTransformer, m, "a method cannot be changed into a ghost method in a refining module: {0}", m.Name);
} else if (!prevMethod.IsGhost && m.IsGhost) {
- reporter.Error(m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name);
+ reporter.Error(MessageSource.RefinementTransformer, m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name);
}
if (m.SignatureIsOmitted) {
Contract.Assert(m.TypeArgs.Count == 0);
Contract.Assert(m.Ins.Count == 0);
Contract.Assert(m.Outs.Count == 0);
- ReportAdditionalInformation(m.SignatureEllipsis, Printer.MethodSignatureToString(prevMethod), 3);
+ reporter.Info(MessageSource.RefinementTransformer, m.SignatureEllipsis, Printer.MethodSignatureToString(prevMethod));
} else {
CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, "method");
CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter");
@@ -823,13 +865,13 @@ namespace Microsoft.Dafny
Contract.Requires(name != null);
Contract.Requires(thing != null);
if (old.Count != nw.Count) {
- reporter.Error(tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines", thing, name, nw.Count, old.Count);
+ reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines", thing, name, nw.Count, old.Count);
} else {
for (int i = 0; i < old.Count; i++) {
var o = old[i];
var n = nw[i];
if (o.Name != n.Name && checkNames) { // if checkNames is false, then just treat the parameters positionally.
- reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name);
} else {
// This explains what we want to do and why:
// switch (o.EqualitySupport) {
@@ -849,7 +891,7 @@ namespace Microsoft.Dafny
// }
// Here's how we actually compute it:
if (o.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.EqualitySupport != n.EqualitySupport) {
- reporter.Error(n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name);
}
}
}
@@ -862,7 +904,7 @@ namespace Microsoft.Dafny
CheckOverrideResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "function", "parameter");
if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType))
{
- reporter.Error(nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it overrides ({2})", nw.Name, nw.ResultType, f.ResultType);
+ reporter.Error(MessageSource.RefinementTransformer, nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it overrides ({2})", nw.Name, nw.ResultType, f.ResultType);
}
}
@@ -882,7 +924,7 @@ namespace Microsoft.Dafny
Contract.Requires(thing != null);
if (old.Count != nw.Count)
{
- reporter.Error(tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it overrides", thing, name, nw.Count, old.Count);
+ reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it overrides", thing, name, nw.Count, old.Count);
}
else
{
@@ -892,14 +934,14 @@ namespace Microsoft.Dafny
var n = nw[i];
if (o.Name != n.Name && checkNames)
{ // if checkNames is false, then just treat the parameters positionally.
- reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being overriden (expected '{1}', found '{2}')", thing, o.Name, n.Name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being overriden (expected '{1}', found '{2}')", thing, o.Name, n.Name);
}
else
{
// Here's how we actually compute it:
if (o.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.EqualitySupport != n.EqualitySupport)
{
- reporter.Error(n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name);
}
}
}
@@ -916,7 +958,7 @@ namespace Microsoft.Dafny
Contract.Requires(parameterKind != null);
if (old.Count != nw.Count)
{
- reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it overrides", thing, name, parameterKind, nw.Count, old.Count);
+ reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it overrides", thing, name, parameterKind, nw.Count, old.Count);
}
else
{
@@ -926,15 +968,15 @@ namespace Microsoft.Dafny
var n = nw[i];
if (!o.IsGhost && n.IsGhost)
{
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-ghost to ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-ghost to ghost", parameterKind, n.Name, thing, name);
}
else if (o.IsGhost && !n.IsGhost)
{
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from ghost to non-ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from ghost to non-ghost", parameterKind, n.Name, thing, name);
}
else if (!ResolvedTypesAreTheSame(o.Type, n.Type))
{
- reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it overrides ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it overrides ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
}
}
}
@@ -948,19 +990,19 @@ namespace Microsoft.Dafny
Contract.Requires(thing != null);
Contract.Requires(parameterKind != null);
if (old.Count != nw.Count) {
- reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
+ reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
} else {
for (int i = 0; i < old.Count; i++) {
var o = old[i];
var n = nw[i];
if (o.Name != n.Name) {
- reporter.Error(n.tok, "there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines", parameterKind, i, n.Name, o.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines", parameterKind, i, n.Name, o.Name, thing, name);
} else if (!o.IsGhost && n.IsGhost) {
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
} else if (o.IsGhost && !n.IsGhost) {
- reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
} else if (!TypesAreSyntacticallyEqual(o.Type, n.Type)) {
- reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
+ reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
}
}
}
@@ -986,7 +1028,7 @@ namespace Microsoft.Dafny
} else if (((SkeletonStatement)cur).S == null) {
// the "..." matches the empty statement sequence
} else {
- reporter.Error(cur.Tok, "skeleton statement does not match old statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "skeleton statement does not match old statement");
}
i++;
} else {
@@ -1040,7 +1082,7 @@ namespace Microsoft.Dafny
Contract.Assert(c.NameReplacements.Count == c.ExprReplacements.Count);
for (int k = 0; k < c.NameReplacements.Count; k++) {
if (subExprs.ContainsKey(c.NameReplacements[k].val)) {
- reporter.Error(c.NameReplacements[k], "replacement definition must contain at most one definition for a given label");
+ reporter.Error(MessageSource.RefinementTransformer, c.NameReplacements[k], "replacement definition must contain at most one definition for a given label");
} else subExprs.Add(c.NameReplacements[k].val, c.ExprReplacements[k]);
}
subber = new SubstitutionCloner(subExprs, rawCloner);
@@ -1061,12 +1103,12 @@ namespace Microsoft.Dafny
oldS = oldStmt.Body[j];
}
if (hoverTextA.Length != 0) {
- ReportAdditionalInformation(c.Tok, hoverTextA, 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.Tok, hoverTextA);
}
if (subber != null && subber.SubstitutionsMade.Count < subber.Exprs.Count) {
foreach (var s in subber.SubstitutionsMade)
subber.Exprs.Remove(s);
- reporter.Error(c.Tok, "could not find labeled expression(s): " + Util.Comma(", ", subber.Exprs.Keys, x => x));
+ reporter.Error(MessageSource.RefinementTransformer, c.Tok, "could not find labeled expression(s): " + Util.Comma(", ", subber.Exprs.Keys, x => x));
}
}
i++;
@@ -1076,7 +1118,7 @@ namespace Microsoft.Dafny
Contract.Assert(c.ConditionOmitted);
var oldAssume = oldS as PredicateStmt;
if (oldAssume == null) {
- reporter.Error(cur.Tok, "assert template does not match inherited statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "assert template does not match inherited statement");
i++;
} else {
// Clone the expression, but among the new assert's attributes, indicate
@@ -1087,7 +1129,7 @@ namespace Microsoft.Dafny
var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);
body.Add(new AssertStmt(new Translator.ForceCheckToken(skel.Tok), new Translator.ForceCheckToken(skel.EndTok),
e, new Attributes("prependAssertToken", new List<Expression>(), attrs)));
- ReportAdditionalInformation(c.ConditionEllipsis, "assume->assert: " + Printer.ExprToString(e), 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, "assume->assert: " + Printer.ExprToString(e));
i++; j++;
}
@@ -1096,13 +1138,13 @@ namespace Microsoft.Dafny
Contract.Assert(c.ConditionOmitted);
var oldAssume = oldS as AssumeStmt;
if (oldAssume == null) {
- reporter.Error(cur.Tok, "assume template does not match inherited statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "assume template does not match inherited statement");
i++;
} else {
var e = refinementCloner.CloneExpr(oldAssume.Expr);
var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);
body.Add(new AssumeStmt(skel.Tok, skel.EndTok, e, attrs));
- ReportAdditionalInformation(c.ConditionEllipsis, Printer.ExprToString(e), 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.ExprToString(e));
i++; j++;
}
@@ -1111,15 +1153,15 @@ namespace Microsoft.Dafny
Contract.Assert(c.ConditionOmitted);
var oldIf = oldS as IfStmt;
if (oldIf == null) {
- reporter.Error(cur.Tok, "if-statement template does not match inherited statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "if-statement template does not match inherited statement");
i++;
} else {
var resultingThen = MergeBlockStmt(skel.Thn, oldIf.Thn);
var resultingElse = MergeElse(skel.Els, oldIf.Els);
var e = refinementCloner.CloneExpr(oldIf.Guard);
- var r = new IfStmt(skel.Tok, skel.EndTok, e, resultingThen, resultingElse);
+ var r = new IfStmt(skel.Tok, skel.EndTok, oldIf.IsExistentialGuard, e, resultingThen, resultingElse);
body.Add(r);
- ReportAdditionalInformation(c.ConditionEllipsis, Printer.GuardToString(e), 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(oldIf.IsExistentialGuard, e));
i++; j++;
}
@@ -1127,16 +1169,16 @@ namespace Microsoft.Dafny
var skel = (WhileStmt)S;
var oldWhile = oldS as WhileStmt;
if (oldWhile == null) {
- reporter.Error(cur.Tok, "while-statement template does not match inherited statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "while-statement template does not match inherited statement");
i++;
} else {
Expression guard;
if (c.ConditionOmitted) {
guard = refinementCloner.CloneExpr(oldWhile.Guard);
- ReportAdditionalInformation(c.ConditionEllipsis, Printer.GuardToString(oldWhile.Guard), 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(false, oldWhile.Guard));
} else {
if (oldWhile.Guard != null) {
- reporter.Error(skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard");
+ reporter.Error(MessageSource.RefinementTransformer, skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard");
}
guard = skel.Guard;
}
@@ -1152,7 +1194,7 @@ namespace Microsoft.Dafny
Contract.Assert(c.ConditionOmitted);
var oldModifyStmt = oldS as ModifyStmt;
if (oldModifyStmt == null) {
- reporter.Error(cur.Tok, "modify template does not match inherited statement");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "modify template does not match inherited statement");
i++;
} else {
var mod = refinementCloner.CloneSpecFrameExpr(oldModifyStmt.Mod);
@@ -1162,13 +1204,13 @@ namespace Microsoft.Dafny
} else if (oldModifyStmt.Body == null) {
mbody = skel.Body;
} else if (skel.Body == null) {
- reporter.Error(cur.Tok, "modify template must have a body if the inherited modify statement does");
+ reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "modify template must have a body if the inherited modify statement does");
mbody = null;
} else {
mbody = MergeBlockStmt(skel.Body, oldModifyStmt.Body);
}
body.Add(new ModifyStmt(skel.Tok, skel.EndTok, mod.Expressions, mod.Attributes, mbody));
- ReportAdditionalInformation(c.ConditionEllipsis, Printer.FrameExprListToString(mod.Expressions), 3);
+ reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.FrameExprListToString(mod.Expressions));
i++; j++;
}
@@ -1284,7 +1326,7 @@ namespace Microsoft.Dafny
var cNew = (IfStmt)cur;
var cOld = oldS as IfStmt;
if (cOld != null && cOld.Guard == null) {
- var r = new IfStmt(cNew.Tok, cNew.EndTok, cNew.Guard, MergeBlockStmt(cNew.Thn, cOld.Thn), MergeElse(cNew.Els, cOld.Els));
+ var r = new IfStmt(cNew.Tok, cNew.EndTok, cNew.IsExistentialGuard, cNew.Guard, MergeBlockStmt(cNew.Thn, cOld.Thn), MergeElse(cNew.Els, cOld.Els));
body.Add(r);
i++; j++;
} else {
@@ -1331,7 +1373,7 @@ namespace Microsoft.Dafny
sep = "\n";
}
if (hoverText.Length != 0) {
- ReportAdditionalInformation(skeleton.EndTok, hoverText, 3);
+ reporter.Info(MessageSource.RefinementTransformer, skeleton.EndTok, hoverText);
}
return new BlockStmt(skeleton.Tok, skeleton.EndTok, body);
}
@@ -1437,7 +1479,7 @@ namespace Microsoft.Dafny
} else {
if (!Contract.Exists(cOld.Decreases.Expressions, e => e is WildcardExpr)) {
// If the previous loop was not specified with "decreases *", then the new loop is not allowed to provide any "decreases" clause.
- reporter.Error(cNew.Decreases.Expressions[0].tok, "a refining loop can provide a decreases clause only if the loop being refined was declared with 'decreases *'");
+ reporter.Error(MessageSource.RefinementTransformer, cNew.Decreases.Expressions[0].tok, "a refining loop can provide a decreases clause only if the loop being refined was declared with 'decreases *'");
}
decr = cNew.Decreases;
}
@@ -1479,9 +1521,9 @@ namespace Microsoft.Dafny
void MergeAddStatement(Statement s, List<Statement> stmtList) {
Contract.Requires(s != null);
Contract.Requires(stmtList != null);
- var prevErrorCount = reporter.ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
CheckIsOkayNewStatement(s, new Stack<string>(), 0);
- if (reporter.ErrorCount == prevErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
stmtList.Add(s);
}
}
@@ -1498,33 +1540,30 @@ namespace Microsoft.Dafny
labels.Push(n.Data.Name);
}
if (s is SkeletonStatement) {
- reporter.Error(s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced");
+ reporter.Error(MessageSource.RefinementTransformer, s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced");
} else if (s is ReturnStmt) {
// allow return statements, but make note of that this requires verifying the postcondition
((ReturnStmt)s).ReverifyPost = true;
} else if (s is YieldStmt) {
- reporter.Error(s, "yield statements are not allowed in skeletons");
+ reporter.Error(MessageSource.RefinementTransformer, s, "yield statements are not allowed in skeletons");
} else if (s is BreakStmt) {
var b = (BreakStmt)s;
if (b.TargetLabel != null ? !labels.Contains(b.TargetLabel) : loopLevels < b.BreakCount) {
- reporter.Error(s, "break statement in skeleton is not allowed to break outside the skeleton fragment");
+ reporter.Error(MessageSource.RefinementTransformer, s, "break statement in skeleton is not allowed to break outside the skeleton fragment");
}
} else if (s is AssignStmt) {
// TODO: To be a refinement automatically (that is, without any further verification), only variables and fields defined
// in this module are allowed. This needs to be checked. If the LHS refers to an l-value that was not declared within
// this module, then either an error should be reported or the Translator needs to know to translate new proof obligations.
var a = (AssignStmt)s;
- reporter.Error(a.Tok, "cannot have assignment statement");
+ reporter.Error(MessageSource.RefinementTransformer, a.Tok, "cannot have assignment statement");
} else if (s is ConcreteUpdateStatement) {
postTasks.Enqueue(() =>
{
- CheckIsOkayUpdateStmt((ConcreteUpdateStatement)s, moduleUnderConstruction, reporter);
+ CheckIsOkayUpdateStmt((ConcreteUpdateStatement)s, moduleUnderConstruction);
});
} else if (s is CallStmt) {
- reporter.Error(s.Tok, "cannot have call statement");
- } else if (s is ForallStmt) {
- if (((ForallStmt)s).Kind == ForallStmt.ParBodyKind.Assign) // allow Proof and Call (as neither touch any existing state)
- reporter.Error(s.Tok, "cannot have forall statement");
+ reporter.Error(MessageSource.RefinementTransformer, s.Tok, "cannot have call statement");
} else {
if (s is WhileStmt || s is AlternativeLoopStmt) {
loopLevels++;
@@ -1540,7 +1579,7 @@ namespace Microsoft.Dafny
}
// Checks that statement stmt, defined in the constructed module m, is a refinement of skip in the parent module
- void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m, ResolutionErrorReporter reporter) {
+ void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m) {
foreach (var lhs in stmt.Lhss) {
var l = lhs.Resolved;
if (l is IdentifierExpr) {
@@ -1548,23 +1587,23 @@ namespace Microsoft.Dafny
Contract.Assert(ident.Var is LocalVariable || ident.Var is Formal); // LHS identifier expressions must be locals or out parameters (ie. formals)
if ((ident.Var is LocalVariable && RefinementToken.IsInherited(((LocalVariable)ident.Var).Tok, m)) || ident.Var is Formal) {
// for some reason, formals are not considered to be inherited.
- reporter.Error(l.tok, "refinement method cannot assign to variable defined in parent module ('{0}')", ident.Var.Name);
+ reporter.Error(MessageSource.RefinementTransformer, l.tok, "refinement method cannot assign to variable defined in parent module ('{0}')", ident.Var.Name);
}
} else if (l is MemberSelectExpr) {
var member = ((MemberSelectExpr)l).Member;
if (RefinementToken.IsInherited(member.tok, m)) {
- reporter.Error(l.tok, "refinement method cannot assign to a field defined in parent module ('{0}')", member.Name);
+ reporter.Error(MessageSource.RefinementTransformer, l.tok, "refinement method cannot assign to a field defined in parent module ('{0}')", member.Name);
}
} else {
// must be an array element
- reporter.Error(l.tok, "new assignments in a refinement method can only assign to state that the module defines (which never includes array elements)");
+ reporter.Error(MessageSource.RefinementTransformer, l.tok, "new assignments in a refinement method can only assign to state that the module defines (which never includes array elements)");
}
}
if (stmt is UpdateStmt) {
var s = (UpdateStmt)stmt;
foreach (var rhs in s.Rhss) {
if (rhs.CanAffectPreviouslyKnownExpressions) {
- reporter.Error(rhs.Tok, "assignment RHS in refinement method is not allowed to affect previously defined state");
+ reporter.Error(MessageSource.RefinementTransformer, rhs.Tok, "assignment RHS in refinement method is not allowed to affect previously defined state");
}
}
}
diff --git a/Source/Dafny/Reporting.cs b/Source/Dafny/Reporting.cs
new file mode 100644
index 00000000..b36efc55
--- /dev/null
+++ b/Source/Dafny/Reporting.cs
@@ -0,0 +1,160 @@
+using Microsoft.Boogie;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Dafny {
+ public enum ErrorLevel {
+ Info, Warning, Error
+ }
+
+ public enum MessageSource {
+ Parser, Resolver, Translator, Rewriter, Other,
+ RefinementTransformer,
+ Cloner
+ }
+
+ public struct ErrorMessage {
+ public IToken token;
+ public string message;
+ public MessageSource source;
+ }
+
+ public abstract class ErrorReporter {
+ public bool ErrorsOnly { get; set; }
+ public Dictionary<ErrorLevel, List<ErrorMessage>> AllMessages { get; private set; }
+
+ protected ErrorReporter() {
+ ErrorsOnly = false;
+ AllMessages = new Dictionary<ErrorLevel, List<ErrorMessage>>();
+ AllMessages[ErrorLevel.Error] = new List<ErrorMessage>();
+ AllMessages[ErrorLevel.Warning] = new List<ErrorMessage>();
+ AllMessages[ErrorLevel.Info] = new List<ErrorMessage>();
+ }
+
+ // This is the only thing that needs to be overriden
+ public virtual bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {
+ bool discard = (ErrorsOnly && level != ErrorLevel.Error) || // Discard non-errors if ErrorsOnly is set
+ (tok is TokenWrapper && !(tok is NestedToken) && !(tok is RefinementToken)); // Discard wrapped tokens, except for nested and refinement
+ if (!discard) {
+ AllMessages[level].Add(new ErrorMessage { token = tok, message = msg });
+ }
+ return !discard;
+ }
+
+ public int Count(ErrorLevel level) {
+ return AllMessages[level].Count;
+ }
+
+ public void Error(MessageSource source, IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Message(source, ErrorLevel.Error, tok, msg);
+ }
+
+ // This method required by the Parser
+ internal void Error(MessageSource source, string filename, int line, int col, string msg) {
+ var tok = new Token(line, col);
+ tok.filename = filename;
+ Error(source, tok, msg);
+ }
+
+ public void Error(MessageSource source, IToken tok, string msg, params object[] args) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Error(source, tok, String.Format(msg, args));
+ }
+
+ public void Error(MessageSource source, Declaration d, string msg, params object[] args) {
+ Contract.Requires(d != null);
+ Contract.Requires(msg != null);
+ Error(source, d.tok, msg, args);
+ }
+
+ public void Error(MessageSource source, Statement s, string msg, params object[] args) {
+ Contract.Requires(s != null);
+ Contract.Requires(msg != null);
+ Error(source, s.Tok, msg, args);
+ }
+
+ public void Error(MessageSource source, NonglobalVariable v, string msg, params object[] args) {
+ Contract.Requires(v != null);
+ Contract.Requires(msg != null);
+ Error(source, v.tok, msg, args);
+ }
+
+ public void Error(MessageSource source, Expression e, string msg, params object[] args) {
+ Contract.Requires(e != null);
+ Contract.Requires(msg != null);
+ Error(source, e.tok, msg, args);
+ }
+
+ public void Warning(MessageSource source, IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Message(source, ErrorLevel.Warning, tok, msg);
+ }
+
+ public void Warning(MessageSource source, IToken tok, string msg, params object[] args) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Warning(source, tok, String.Format(msg, args));
+ }
+
+ public void Info(MessageSource source, IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Message(source, ErrorLevel.Info, tok, msg);
+ }
+
+ public void Info(MessageSource source, IToken tok, string msg, params object[] args) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Info(source, tok, String.Format(msg, args));
+ }
+
+ public static string ErrorToString(ErrorLevel header, IToken tok, string msg) {
+ return ErrorToString_Internal(": " + header.ToString(), tok.filename, tok.line, tok.col, ": " + msg);
+ }
+
+ public static string ErrorToString(ErrorLevel header, string filename, int oneBasedLine, int oneBasedColumn, string msg) {
+ return ErrorToString_Internal(": " + header.ToString(), filename, oneBasedLine, oneBasedColumn, ": " + msg);
+ }
+
+ public static string ErrorToString_Internal(string header, string filename, int oneBasedLine, int oneBasedColumn, string msg) {
+ return String.Format("{0}({1},{2}){3}{4}", filename, oneBasedLine, oneBasedColumn - 1, header, msg ?? "");
+ }
+ }
+
+ public class ConsoleErrorReporter : ErrorReporter {
+ private ConsoleColor ColorForLevel(ErrorLevel level) {
+ switch (level) {
+ case ErrorLevel.Error:
+ return ConsoleColor.Red;
+ case ErrorLevel.Warning:
+ return ConsoleColor.Yellow;
+ case ErrorLevel.Info:
+ return ConsoleColor.Green;
+ default:
+ throw new cce.UnreachableException();
+ }
+ }
+
+ public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {
+ if (base.Message(source, level, tok, msg) && ((DafnyOptions.O != null && DafnyOptions.O.PrintTooltips) || level != ErrorLevel.Info)) {
+ // Extra indent added to make it easier to distinguish multiline error messages for clients that rely on the CLI
+ msg = msg.Replace(Environment.NewLine, Environment.NewLine + " ");
+
+ ConsoleColor previousColor = Console.ForegroundColor;
+ Console.ForegroundColor = ColorForLevel(level);
+ Console.WriteLine(ErrorToString(level, tok, msg));
+ Console.ForegroundColor = previousColor;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index f7ec135b..b6e783b4 100644
--- a/Source/Dafny/Resolver.cs
+++ b/Source/Dafny/Resolver.cs
@@ -12,67 +12,11 @@ using Microsoft.Boogie;
namespace Microsoft.Dafny
{
- public class ResolutionErrorReporter
- {
- public int ErrorCount = 0;
-
- /// <summary>
- /// This method is virtual, because it is overridden in the VSX plug-in for Dafny.
- /// </summary>
- public virtual void Error(IToken tok, string msg, params object[] args) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- ConsoleColor col = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine("{0}({1},{2}): Error: {3}",
- DafnyOptions.Clo.UseBaseNameForFileName ? System.IO.Path.GetFileName(tok.filename) : tok.filename, tok.line, tok.col - 1,
- string.Format(msg, args));
- Console.ForegroundColor = col;
- ErrorCount++;
- }
- public void Error(Declaration d, string msg, params object[] args) {
- Contract.Requires(d != null);
- Contract.Requires(msg != null);
- Error(d.tok, msg, args);
- }
- public void Error(Statement s, string msg, params object[] args) {
- Contract.Requires(s != null);
- Contract.Requires(msg != null);
- Error(s.Tok, msg, args);
- }
- public void Error(NonglobalVariable v, string msg, params object[] args) {
- Contract.Requires(v != null);
- Contract.Requires(msg != null);
- Error(v.tok, msg, args);
- }
- public void Error(Expression e, string msg, params object[] args) {
- Contract.Requires(e != null);
- Contract.Requires(msg != null);
- Error(e.tok, msg, args);
- }
- public void Warning(IToken tok, string msg, params object[] args) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- ConsoleColor col = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine("{0}({1},{2}): Warning: {3}",
- DafnyOptions.Clo.UseBaseNameForFileName ? System.IO.Path.GetFileName(tok.filename) : tok.filename, tok.line, tok.col - 1,
- string.Format(msg, args));
- Console.ForegroundColor = col;
- }
- }
-
- public struct AdditionalInformation
- {
- public IToken Token;
- public string Text;
- public int Length;
- }
-
- public class Resolver : ResolutionErrorReporter
+ public class Resolver
{
readonly BuiltIns builtIns;
+ readonly ErrorReporter reporter;
ModuleSignature moduleInfo = null;
FreshIdGenerator defaultTempVarIdGenerator;
@@ -91,18 +35,6 @@ namespace Microsoft.Dafny
return defaultTempVarIdGenerator.FreshId(prefix);
}
- public Action<AdditionalInformation> AdditionalInformationReporter;
-
- internal void ReportAdditionalInformation(IToken token, string text, int length)
- {
- Contract.Requires(token != null);
- Contract.Requires(text != null);
- Contract.Requires(0 <= length);
- if (AdditionalInformationReporter != null) {
- AdditionalInformationReporter(new AdditionalInformation { Token = token, Text = text, Length = length });
- }
- }
-
interface IAmbiguousThing<Thing>
{
/// <summary>
@@ -251,6 +183,7 @@ namespace Microsoft.Dafny
public Resolver(Program prog) {
Contract.Requires(prog != null);
builtIns = prog.BuiltIns;
+ reporter = prog.reporter;
// Populate the members of the basic types
var trunc = new SpecialField(Token.NoToken, "Trunc", "ToBigInteger()", "", "", false, false, false, Type.Int, null);
basicTypeMembers[(int)BasicTypeVariety.Real].Add(trunc.Name, trunc);
@@ -264,22 +197,49 @@ namespace Microsoft.Dafny
Contract.Invariant(cce.NonNullDictionaryAndValues(datatypeCtors) && Contract.ForAll(datatypeCtors.Values, v => cce.NonNullDictionaryAndValues(v)));
}
+ /// <summary>
+ /// Check that now two modules that are being compiled have the same CompileName.
+ ///
+ /// This could happen if they are given the same name using the 'extern' declaration modifier.
+ /// </summary>
+ /// <param name="prog">The Dafny program being compiled.</param>
+ void CheckDupModuleNames(Program prog)
+ {
+ // Check that none of the modules have the same CompileName.
+ Dictionary<string, ModuleDefinition> compileNameMap = new Dictionary<string, ModuleDefinition>();
+ foreach (ModuleDefinition m in prog.CompileModules) {
+ if (m.IsAbstract) {
+ // the purpose of an abstract module is to skip compilation
+ continue;
+ }
+ string compileName = m.CompileName;
+ ModuleDefinition priorModDef;
+ if (compileNameMap.TryGetValue(compileName, out priorModDef)) {
+ reporter.Error(MessageSource.Resolver, m.tok,
+ "Modules '{0}' and '{1}' both have CompileName '{2}'.",
+ priorModDef.tok.val, m.tok.val, compileName);
+ }
+ else {
+ compileNameMap.Add(compileName, m);
+ }
+ }
+ }
public void ResolveProgram(Program prog) {
Contract.Requires(prog != null);
- var origErrorCount = ErrorCount;
+ var origErrorCount = reporter.Count(ErrorLevel.Error); //TODO: This is used further below, but not in the >0 comparisons in the next few lines. Is that right?
var bindings = new ModuleBindings(null);
var b = BindModuleNames(prog.DefaultModuleDef, bindings);
bindings.BindName("_module", prog.DefaultModule, b);
- if (ErrorCount > 0) { return; } // if there were errors, then the implict ModuleBindings data structure invariant
+ if (reporter.Count(ErrorLevel.Error) > 0) { return; } // if there were errors, then the implict ModuleBindings data structure invariant
// is violated, so Processing dependencies will not succeed.
ProcessDependencies(prog.DefaultModule, b, dependencies);
// check for cycles in the import graph
List<ModuleDecl> cycle = dependencies.TryFindCycle();
if (cycle != null) {
var cy = Util.Comma(" -> ", cycle, m => m.Name);
- Error(cycle[0], "module definition contains a cycle (note: parent modules implicitly depend on submodules): {0}", cy);
+ reporter.Error(MessageSource.Resolver, cycle[0], "module definition contains a cycle (note: parent modules implicitly depend on submodules): {0}", cy);
}
- if (ErrorCount > 0) { return; } // give up on trying to resolve anything else
+ if (reporter.Count(ErrorLevel.Error) > 0) { return; } // give up on trying to resolve anything else
// fill in module heights
List<ModuleDecl> sortedDecls = dependencies.TopologicallySortedComponents();
@@ -295,16 +255,51 @@ namespace Microsoft.Dafny
}
var rewriters = new List<IRewriter>();
- var refinementTransformer = new RefinementTransformer(this, AdditionalInformationReporter, prog);
+ var refinementTransformer = new RefinementTransformer(prog);
rewriters.Add(refinementTransformer);
- rewriters.Add(new AutoContractsRewriter());
- var opaqueRewriter = new OpaqueFunctionRewriter(this);
- rewriters.Add(new AutoReqFunctionRewriter(this, opaqueRewriter));
+ rewriters.Add(new AutoContractsRewriter(reporter));
+ var opaqueRewriter = new OpaqueFunctionRewriter(this.reporter);
+ rewriters.Add(new AutoReqFunctionRewriter(this.reporter, opaqueRewriter));
rewriters.Add(opaqueRewriter);
- rewriters.Add(new TimeLimitRewriter());
+ rewriters.Add(new TimeLimitRewriter(reporter));
+ rewriters.Add(new ForallStmtRewriter(reporter));
+
+ if (DafnyOptions.O.AutoTriggers) {
+ rewriters.Add(new QuantifierSplittingRewriter(reporter));
+ rewriters.Add(new TriggerGeneratingRewriter(reporter));
+ }
+
+ rewriters.Add(new InductionRewriter(reporter));
systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule, false);
prog.CompileModules.Add(prog.BuiltIns.SystemModule);
+
+ // first, we need to detect which top-level modules have exclusive refinement relationships.
+ foreach (ModuleDecl decl in sortedDecls) {
+ if (decl is LiteralModuleDecl) {
+ var literalDecl = (LiteralModuleDecl)decl;
+ var m = literalDecl.ModuleDef;
+ if (m.RefinementBaseRoot != null) {
+ if (m.IsExclusiveRefinement) {
+ foreach (var d in sortedDecls) {
+ // refinement dependencies won't be later in the sorted module list than the one we're looking at.
+ if (Object.ReferenceEquals(d, decl)) {
+ break;
+ }
+ if (d is LiteralModuleDecl) {
+ var ld = (LiteralModuleDecl)d;
+ // currently, only exclusive refinements of top-level modules are supported.
+ if (string.Equals(m.RefinementBaseName[0].val, m.RefinementBaseRoot.Name, StringComparison.InvariantCulture)
+ && string.Equals(m.RefinementBaseName[0].val, ld.ModuleDef.Name, StringComparison.InvariantCulture)) {
+ ld.ModuleDef.ExclusiveRefinementCount += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
foreach (var decl in sortedDecls) {
if (decl is LiteralModuleDecl) {
// The declaration is a literal module, so it has members and such that we need
@@ -318,7 +313,7 @@ namespace Microsoft.Dafny
var literalDecl = (LiteralModuleDecl)decl;
var m = literalDecl.ModuleDef;
- var errorCount = ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
foreach (var r in rewriters) {
r.PreResolve(m);
}
@@ -327,18 +322,21 @@ namespace Microsoft.Dafny
literalDecl.Signature.Refines = refinementTransformer.RefinedSig;
var sig = literalDecl.Signature;
// set up environment
- var preResolveErrorCount = ErrorCount;
+ var preResolveErrorCount = reporter.Count(ErrorLevel.Error);
ResolveModuleDefinition(m, sig);
+ ResolveModuleExport(literalDecl, sig);
foreach (var r in rewriters) {
- if (ErrorCount != preResolveErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) != preResolveErrorCount) {
break;
}
r.PostResolve(m);
}
- if (ErrorCount == errorCount && !m.IsAbstract) {
+ if (reporter.Count(ErrorLevel.Error) == errorCount && !m.IsAbstract) {
// compilation should only proceed if everything is good, including the signature (which preResolveErrorCount does not include);
Contract.Assert(!useCompileSignatures);
useCompileSignatures = true; // set Resolver-global flag to indicate that Signatures should be followed to their CompiledSignature
+ var oldErrorsOnly = reporter.ErrorsOnly;
+ reporter.ErrorsOnly = true; // turn off warning reporting for the clone
var nw = new Cloner().CloneModuleDefinition(m, m.CompileName + "_Compile");
var compileSig = RegisterTopLevelDecls(nw, true);
compileSig.Refines = refinementTransformer.RefinedSig;
@@ -346,12 +344,13 @@ namespace Microsoft.Dafny
ResolveModuleDefinition(nw, compileSig);
prog.CompileModules.Add(nw);
useCompileSignatures = false; // reset the flag
+ reporter.ErrorsOnly = oldErrorsOnly;
}
} else if (decl is AliasModuleDecl) {
var alias = (AliasModuleDecl)decl;
// resolve the path
ModuleSignature p;
- if (ResolvePath(alias.Root, alias.Path, out p, this)) {
+ if (ResolvePath(alias.Root, alias.Path, out p, reporter)) {
alias.Signature = p;
} else {
alias.Signature = new ModuleSignature(); // there was an error, give it a valid but empty signature
@@ -359,29 +358,41 @@ namespace Microsoft.Dafny
} else if (decl is ModuleFacadeDecl) {
var abs = (ModuleFacadeDecl)decl;
ModuleSignature p;
- if (ResolvePath(abs.Root, abs.Path, out p, this)) {
- abs.Signature = MakeAbstractSignature(p, abs.FullCompileName, abs.Height, prog.Modules);
+ if (ResolvePath(abs.Root, abs.Path, out p, reporter)) {
abs.OriginalSignature = p;
- ModuleSignature compileSig;
- if (abs.CompilePath != null) {
- if (ResolvePath(abs.CompileRoot, abs.CompilePath, out compileSig, this)) {
- if (refinementTransformer.CheckIsRefinement(compileSig, p)) {
- abs.Signature.CompileSignature = compileSig;
- } else {
- Error(abs.CompilePath[0],
- "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of " + Util.Comma(".", abs.Path, x => x.val));
+ // ModuleDefinition.ExclusiveRefinement may not be set at this point but ExclusiveRefinementCount will be.
+ if (0 == abs.Root.Signature.ModuleDef.ExclusiveRefinementCount) {
+ abs.Signature = MakeAbstractSignature(p, abs.FullCompileName, abs.Height, prog.Modules);
+ ModuleSignature compileSig;
+ if (abs.CompilePath != null) {
+ if (ResolvePath(abs.CompileRoot, abs.CompilePath, out compileSig, reporter)) {
+ if (refinementTransformer.CheckIsRefinement(compileSig, p)) {
+ abs.Signature.CompileSignature = compileSig;
+ } else {
+ reporter.Error(MessageSource.Resolver,
+ abs.CompilePath[0],
+ "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of "
+ + Util.Comma(".", abs.Path, x => x.val));
+ }
+ abs.Signature.IsAbstract = compileSig.IsAbstract;
+ // always keep the ghost information, to supress a spurious error message when the compile module isn't actually a refinement
}
- abs.Signature.IsGhost = compileSig.IsGhost;
- // always keep the ghost information, to supress a spurious error message when the compile module isn't actually a refinement
}
+ } else {
+ abs.Signature = p;
}
} else {
abs.Signature = new ModuleSignature(); // there was an error, give it a valid but empty signature
}
+ } else if (decl is ModuleExportDecl) {
+ ModuleExportDecl export = (ModuleExportDecl)decl;
+ export.Signature = new ModuleSignature();
+ export.Signature.IsAbstract = false;
+ export.Signature.ModuleDef = null;
} else { Contract.Assert(false); }
Contract.Assert(decl.Signature != null);
}
- if (ErrorCount != origErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) != origErrorCount) {
// do nothing else
return;
}
@@ -437,7 +448,7 @@ namespace Microsoft.Dafny
}
foreach (var module in prog.Modules) {
foreach (var iter in ModuleDefinition.AllIteratorDecls(module.TopLevelDecls)) {
- ReportAdditionalInformation(iter.tok, Printer.IteratorClassToString(iter), iter.Name.Length);
+ reporter.Info(MessageSource.Resolver, iter.tok, Printer.IteratorClassToString(iter));
}
}
// fill in other additional information
@@ -455,6 +466,34 @@ namespace Microsoft.Dafny
}
}
}
+
+ // Determine, for each function, whether someone tries to adjust its fuel parameter
+ foreach (var module in prog.Modules) {
+ CheckForFuelAdjustments(module.tok, module.Attributes, module);
+ foreach (var clbl in ModuleDefinition.AllItersAndCallables(module.TopLevelDecls)) {
+ Statement body = null;
+ if (clbl is Method) {
+ body = ((Method)clbl).Body;
+ CheckForFuelAdjustments(clbl.Tok,((Method)clbl).Attributes, module);
+ } else if (clbl is IteratorDecl) {
+ body = ((IteratorDecl)clbl).Body;
+ CheckForFuelAdjustments(clbl.Tok, ((IteratorDecl)clbl).Attributes, module);
+ } else if (clbl is Function) {
+ CheckForFuelAdjustments(clbl.Tok, ((Function)clbl).Attributes, module);
+ var c = new FuelAdjustment_Visitor(this);
+ var bodyExpr = ((Function)clbl).Body;
+ if (bodyExpr != null) {
+ c.Visit(bodyExpr, new FuelAdjustment_Context(module));
+ }
+ }
+ if (body != null) {
+ var c = new FuelAdjustment_Visitor(this);
+ c.Visit(body, new FuelAdjustment_Context(module));
+ }
+ }
+ }
+
+ CheckDupModuleNames(prog);
}
void FillInDefaultDecreasesClauses(Program prog)
@@ -487,17 +526,10 @@ namespace Microsoft.Dafny
showIt = ((Method)m).IsRecursive;
}
if (showIt) {
- s += "decreases ";
- if (m.Decreases.Expressions.Count != 0) {
- string sep = "";
- foreach (var d in m.Decreases.Expressions) {
- s += sep + Printer.ExprToString(d);
- sep = ", ";
- }
- }
+ s += "decreases " + Util.Comma(", ", m.Decreases.Expressions, Printer.ExprToString);
// Note, in the following line, we use the location information for "clbl", not "m". These
// are the same, except in the case where "clbl" is a CoLemma and "m" is a prefix lemma.
- ReportAdditionalInformation(clbl.Tok, s, clbl.Tok.val.Length);
+ reporter.Info(MessageSource.Resolver, clbl.Tok, s);
}
}
}
@@ -520,7 +552,7 @@ namespace Microsoft.Dafny
var decr = clbl.Decreases.Expressions;
if (DafnyOptions.O.Dafnycc) {
if (decr.Count > 1) {
- Error(decr[1].tok, "In dafnycc mode, only one decreases expression is allowed");
+ reporter.Error(MessageSource.Resolver, decr[1].tok, "In dafnycc mode, only one decreases expression is allowed");
}
// In dafnycc mode, only consider first argument
if (decr.Count == 0 && clbl.Ins.Count > 0) {
@@ -597,18 +629,18 @@ namespace Microsoft.Dafny
bvars.Add(oVar);
return
- new SetComprehension(e.tok, bvars,
+ new SetComprehension(e.tok, true, bvars,
new BinaryExpr(e.tok, BinaryExpr.Opcode.In, obj,
new ApplyExpr(e.tok, e, bexprs)
{
- Type = new SetType(new ObjectType())
+ Type = new SetType(true, new ObjectType())
})
{
ResolvedOp = BinaryExpr.ResolvedOpcode.InSet,
Type = Type.Bool
}, obj, null)
{
- Type = new SetType(new ObjectType())
+ Type = new SetType(true, new ObjectType())
};
} else {
return e;
@@ -646,8 +678,8 @@ namespace Microsoft.Dafny
var sInE = new BinaryExpr(e.tok, BinaryExpr.Opcode.In, bvIE, e);
sInE.ResolvedOp = BinaryExpr.ResolvedOpcode.InSeq; // resolve here
sInE.Type = Type.Bool; // resolve here
- var s = new SetComprehension(e.tok, new List<BoundVar>() { bv }, sInE, bvIE, null);
- s.Type = new SetType(new ObjectType()); // resolve here
+ var s = new SetComprehension(e.tok, true, new List<BoundVar>() { bv }, sInE, bvIE, null);
+ s.Type = new SetType(true, new ObjectType()); // resolve here
sets.Add(s);
} else {
// e is already a set
@@ -657,20 +689,20 @@ namespace Microsoft.Dafny
}
}
if (singletons != null) {
- Expression display = new SetDisplayExpr(singletons[0].tok, singletons);
- display.Type = new SetType(new ObjectType()); // resolve here
+ Expression display = new SetDisplayExpr(singletons[0].tok, true, singletons);
+ display.Type = new SetType(true, new ObjectType()); // resolve here
sets.Add(display);
}
if (sets.Count == 0) {
- Expression emptyset = new SetDisplayExpr(Token.NoToken, new List<Expression>());
- emptyset.Type = new SetType(new ObjectType()); // resolve here
+ Expression emptyset = new SetDisplayExpr(Token.NoToken, true, new List<Expression>());
+ emptyset.Type = new SetType(true, new ObjectType()); // resolve here
return emptyset;
} else {
Expression s = sets[0];
for (int i = 1; i < sets.Count; i++) {
BinaryExpr union = new BinaryExpr(s.tok, BinaryExpr.Opcode.Add, s, sets[i]);
union.ResolvedOp = BinaryExpr.ResolvedOpcode.Union; // resolve here
- union.Type = new SetType(new ObjectType()); // resolve here
+ union.Type = new SetType(true, new ObjectType()); // resolve here
s = union;
}
return s;
@@ -678,18 +710,117 @@ namespace Microsoft.Dafny
}
private void ResolveModuleDefinition(ModuleDefinition m, ModuleSignature sig) {
+ Contract.Requires(AllTypeConstraints.Count == 0);
+ Contract.Ensures(AllTypeConstraints.Count == 0);
moduleInfo = MergeSignature(sig, systemNameInfo);
// resolve
var datatypeDependencies = new Graph<IndDatatypeDecl>();
var codatatypeDependencies = new Graph<CoDatatypeDecl>();
- int prevErrorCount = ErrorCount;
- ResolveAttributes(m.Attributes, new ResolveOpts(new NoContext(m.Module), false));
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
ResolveTopLevelDecls_Signatures(m, m.TopLevelDecls, datatypeDependencies, codatatypeDependencies);
- if (ErrorCount == prevErrorCount) {
- ResolveTopLevelDecls_Meat(m.TopLevelDecls, datatypeDependencies, codatatypeDependencies);
+ Contract.Assert(AllTypeConstraints.Count == 0); // signature resolution does not add any type constraints
+ ResolveAttributes(m.Attributes, new ResolveOpts(new NoContext(m.Module), false)); // Must follow ResolveTopLevelDecls_Signatures, in case attributes refer to members
+ SolveAllTypeConstraints(); // solve any type constraints entailed by the attributes
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
+ ResolveTopLevelDecls_Core(m.TopLevelDecls, datatypeDependencies, codatatypeDependencies);
+ }
+ }
+
+ // Resolve the exports and detect cycles.
+ private void ResolveModuleExport(LiteralModuleDecl literalDecl, ModuleSignature sig) {
+ ModuleDefinition m = literalDecl.ModuleDef;
+ literalDecl.DefaultExport = sig;
+ Graph<ModuleExportDecl> exportDependencies = new Graph<ModuleExportDecl>();
+ foreach (TopLevelDecl toplevel in m.TopLevelDecls) {
+ if (toplevel is ModuleExportDecl) {
+ ModuleExportDecl d = (ModuleExportDecl) toplevel;
+ exportDependencies.AddVertex(d);
+ foreach (string s in d.Extends) {
+ TopLevelDecl top;
+ if (sig.TopLevels.TryGetValue(s, out top) && top is ModuleExportDecl) {
+ ModuleExportDecl extend = (ModuleExportDecl) top;
+ d.ExtendDecls.Add(extend);
+ exportDependencies.AddEdge(d, extend);
+ } else {
+ reporter.Error(MessageSource.Resolver, m.tok, s + " must be an export of " + m.Name + " to be extended");
+ }
+ }
+ foreach (ExportSignature export in d.Exports) {
+ // check to see if it is a datatype or a member or
+ // static function or method in the enclosing module or its imports
+ TopLevelDecl decl;
+ MemberDecl member;
+ string name = export.Name;
+ if (sig.TopLevels.TryGetValue(name, out decl)) {
+ // Member of the enclosing module
+ export.Decl = decl;
+ } else if (sig.StaticMembers.TryGetValue(name, out member)) {
+ export.Decl = member;
+ } else {
+ reporter.Error(MessageSource.Resolver, d.tok, name + " must be a member of " + m.Name + " to be exported");
+ }
+ }
+ }
}
- }
+ // detect cycles in the extend
+ var cycle = exportDependencies.TryFindCycle();
+ if (cycle != null) {
+ var cy = Util.Comma(" -> ", cycle, c => c.Name);
+ reporter.Error(MessageSource.Resolver, cycle[0], "module export contains a cycle: {0}", cy);
+ return;
+ }
+
+ // fill in the exports for the extends.
+ List<ModuleExportDecl> sortedDecls = exportDependencies.TopologicallySortedComponents();
+ ModuleExportDecl defaultExport = null;
+ foreach (ModuleExportDecl decl in sortedDecls) {
+ if (decl.IsDefault) {
+ if (defaultExport == null) {
+ defaultExport = decl;
+ } else {
+ reporter.Error(MessageSource.Resolver, m.tok, "more than one default export declared in module {0}", m.Name);
+ }
+ }
+ // fill in export signature
+ ModuleSignature signature = decl.Signature;
+ foreach (ModuleExportDecl extend in decl.ExtendDecls) {
+ ModuleSignature s = extend.Signature;
+ foreach (var kv in s.TopLevels) {
+ if (!signature.TopLevels.ContainsKey(kv.Key)) {
+ signature.TopLevels.Add(kv.Key, kv.Value);
+ }
+ }
+ foreach (var kv in s.Ctors) {
+ if (!signature.Ctors.ContainsKey(kv.Key)) {
+ signature.Ctors.Add(kv.Key, kv.Value);
+ }
+ }
+ foreach (var kv in s.StaticMembers) {
+ if (!signature.StaticMembers.ContainsKey(kv.Key)) {
+ signature.StaticMembers.Add(kv.Key, kv.Value);
+ }
+ }
+ }
+ foreach (ExportSignature export in decl.Exports) {
+ if (export.Decl is TopLevelDecl) {
+ signature.TopLevels.Add(export.Name, (TopLevelDecl)export.Decl);
+ } else if (export.Decl is MemberDecl) {
+ signature.StaticMembers.Add(export.Name, (MemberDecl)export.Decl);
+ }
+ }
+ }
+
+ // set the default export if it exists
+ if (defaultExport != null) {
+ literalDecl.DefaultExport = defaultExport.Signature;
+ } else {
+ // if there is at least one exported view, but no exported view marked as default, then defaultExport should be null.
+ if (sortedDecls.Count > 0) {
+ literalDecl.DefaultExport = null;
+ }
+ }
+ }
public class ModuleBindings
{
@@ -744,17 +875,17 @@ namespace Microsoft.Dafny
var subdecl = (LiteralModuleDecl)tld;
var subBindings = BindModuleNames(subdecl.ModuleDef, bindings);
if (!bindings.BindName(subdecl.Name, subdecl, subBindings)) {
- Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
+ reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
} else if (tld is ModuleFacadeDecl) {
var subdecl = (ModuleFacadeDecl)tld;
if (!bindings.BindName(subdecl.Name, subdecl, null)) {
- Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
+ reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
} else if (tld is AliasModuleDecl) {
var subdecl = (AliasModuleDecl)tld;
if (!bindings.BindName(subdecl.Name, subdecl, null)) {
- Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
+ reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
}
}
@@ -765,9 +896,9 @@ namespace Microsoft.Dafny
if (m.RefinementBaseName != null) {
ModuleDecl other;
if (!bindings.TryLookup(m.RefinementBaseName[0], out other)) {
- Error(m.RefinementBaseName[0], "module {0} named as refinement base does not exist", m.RefinementBaseName[0].val);
+ reporter.Error(MessageSource.Resolver, m.RefinementBaseName[0], "module {0} named as refinement base does not exist", m.RefinementBaseName[0].val);
} else if (other is LiteralModuleDecl && ((LiteralModuleDecl)other).ModuleDef == m) {
- Error(m.RefinementBaseName[0], "module cannot refine itself: {0}", m.RefinementBaseName[0].val);
+ reporter.Error(MessageSource.Resolver, m.RefinementBaseName[0], "module cannot refine itself: {0}", m.RefinementBaseName[0].val);
} else {
Contract.Assert(other != null); // follows from postcondition of TryGetValue
dependencies.AddEdge(decl, other);
@@ -791,7 +922,7 @@ namespace Microsoft.Dafny
var alias = moduleDecl as AliasModuleDecl;
ModuleDecl root;
if (!bindings.TryLookupIgnore(alias.Path[0], out root, alias))
- Error(alias.tok, ModuleNotFoundErrorMessage(0, alias.Path));
+ reporter.Error(MessageSource.Resolver, alias.tok, ModuleNotFoundErrorMessage(0, alias.Path));
else {
dependencies.AddEdge(moduleDecl, root);
alias.Root = root;
@@ -800,14 +931,14 @@ namespace Microsoft.Dafny
var abs = moduleDecl as ModuleFacadeDecl;
ModuleDecl root;
if (!bindings.TryLookup(abs.Path[0], out root))
- Error(abs.tok, ModuleNotFoundErrorMessage(0, abs.Path));
+ reporter.Error(MessageSource.Resolver, abs.tok, ModuleNotFoundErrorMessage(0, abs.Path));
else {
dependencies.AddEdge(moduleDecl, root);
abs.Root = root;
}
if (abs.CompilePath != null) {
if (!bindings.TryLookup(abs.CompilePath[0], out root))
- Error(abs.tok, ModuleNotFoundErrorMessage(0, abs.CompilePath));
+ reporter.Error(MessageSource.Resolver, abs.tok, ModuleNotFoundErrorMessage(0, abs.CompilePath));
else {
dependencies.AddEdge(moduleDecl, root);
abs.CompileRoot = root;
@@ -842,37 +973,76 @@ namespace Microsoft.Dafny
foreach (var kv in m.StaticMembers) {
info.StaticMembers[kv.Key] = kv.Value;
}
- info.IsGhost = m.IsGhost;
+ info.IsAbstract = m.IsAbstract;
return info;
}
ModuleSignature RegisterTopLevelDecls(ModuleDefinition moduleDef, bool useImports) {
Contract.Requires(moduleDef != null);
var sig = new ModuleSignature();
sig.ModuleDef = moduleDef;
- sig.IsGhost = moduleDef.IsAbstract;
+ sig.IsAbstract = moduleDef.IsAbstract;
List<TopLevelDecl> declarations = moduleDef.TopLevelDecls;
- if (useImports) {
- // First go through and add anything from the opened imports
- foreach (var im in declarations) {
- if (im is ModuleDecl && ((ModuleDecl)im).Opened) {
- var s = GetSignature(((ModuleDecl)im).Signature);
+ // First go through and add anything from the opened imports
+ foreach (var im in declarations) {
+ if (im is ModuleDecl && ((ModuleDecl)im).Opened) {
+ var s = GetSignature(((ModuleDecl)im).Signature);
+
+ if (useImports || DafnyOptions.O.IronDafny) {
// classes:
foreach (var kv in s.TopLevels) {
- TopLevelDecl d;
- if (sig.TopLevels.TryGetValue(kv.Key, out d)) {
- sig.TopLevels[kv.Key] = AmbiguousTopLevelDecl.Create(moduleDef, d, kv.Value);
- } else {
- sig.TopLevels.Add(kv.Key, kv.Value);
+ // IronDafny: we need to pull the members of the opened module's _default class in so that they can be merged.
+ if (useImports || string.Equals(kv.Key, "_default", StringComparison.InvariantCulture)) {
+ TopLevelDecl d;
+ if (sig.TopLevels.TryGetValue(kv.Key, out d)) {
+ bool resolved = false;
+ if (DafnyOptions.O.IronDafny) {
+ // sometimes, we need to compare two type synonyms in order to come up with a decision regarding substitution.
+ var aliased1 = Object.ReferenceEquals(kv.Value, d);
+ if (!aliased1) {
+ var a = d;
+ while (a.ExclusiveRefinement != null) {
+ a = a.ExclusiveRefinement;
+ }
+ var b = kv.Value;
+ while (b.ExclusiveRefinement != null) {
+ b = b.ExclusiveRefinement;
+ }
+ if (a is TypeSynonymDecl && b is TypeSynonymDecl) {
+ aliased1 = UnifyTypes(((TypeSynonymDecl)a).Rhs, ((TypeSynonymDecl)b).Rhs);
+ } else {
+ aliased1 = Object.ReferenceEquals(a, b);
+ }
+ }
+ if (aliased1 ||
+ Object.ReferenceEquals(kv.Value.ClonedFrom, d) ||
+ Object.ReferenceEquals(d.ClonedFrom, kv.Value) ||
+ Object.ReferenceEquals(kv.Value.ExclusiveRefinement, d)) {
+ sig.TopLevels[kv.Key] = kv.Value;
+ resolved = true;
+ }
+ }
+ if (!resolved) {
+ sig.TopLevels[kv.Key] = AmbiguousTopLevelDecl.Create(moduleDef, d, kv.Value);
+ }
+ } else {
+ sig.TopLevels.Add(kv.Key, kv.Value);
+ }
}
}
+ }
+
+ if (useImports) {
// constructors:
foreach (var kv in s.Ctors) {
Tuple<DatatypeCtor, bool> pair;
if (sig.Ctors.TryGetValue(kv.Key, out pair)) {
// The same ctor can be imported from two different imports (e.g "diamond" imports), in which case,
// they are not duplicates.
- if (kv.Value.Item1 != pair.Item1) {
+ if (!Object.ReferenceEquals(kv.Value.Item1, pair.Item1) &&
+ (!DafnyOptions.O.IronDafny ||
+ (!Object.ReferenceEquals(kv.Value.Item1.ClonedFrom, pair.Item1) &&
+ !Object.ReferenceEquals(kv.Value.Item1, pair.Item1.ClonedFrom)))) {
// mark it as a duplicate
sig.Ctors[kv.Key] = new Tuple<DatatypeCtor, bool>(pair.Item1, true);
}
@@ -881,19 +1051,74 @@ namespace Microsoft.Dafny
sig.Ctors.Add(kv.Key, kv.Value);
}
}
+ }
+
+ if (useImports || DafnyOptions.O.IronDafny) {
// static members:
foreach (var kv in s.StaticMembers) {
MemberDecl md;
if (sig.StaticMembers.TryGetValue(kv.Key, out md)) {
+ var resolved = false;
+ if (DafnyOptions.O.IronDafny) {
+ var aliased0 = Object.ReferenceEquals(kv.Value, md) || Object.ReferenceEquals(kv.Value.ClonedFrom, md) || Object.ReferenceEquals(md.ClonedFrom, kv.Value);
+ var aliased1 = aliased0;
+ if (!aliased0) {
+ var a = kv.Value.EnclosingClass;
+ while (a != null &&
+ (a.ExclusiveRefinement != null || a.ClonedFrom != null)) {
+ if (a.ClonedFrom != null) {
+ a = (TopLevelDecl)a.ClonedFrom;
+ } else {
+ Contract.Assert(a.ExclusiveRefinement != null);
+ a = a.ExclusiveRefinement;
+ }
+ }
+ var b = md.EnclosingClass;
+ while (b != null &&
+ (b.ExclusiveRefinement != null || b.ClonedFrom != null)) {
+ if (b.ClonedFrom != null) {
+ b = (TopLevelDecl)b.ClonedFrom;
+ } else {
+ Contract.Assert(b.ExclusiveRefinement != null);
+ b = b.ExclusiveRefinement;
+ }
+ }
+ aliased1 = Object.ReferenceEquals(a, b);
+ }
+ if (aliased0 || aliased1) {
+ if (kv.Value.EnclosingClass != null &&
+ md.EnclosingClass != null &&
+ md.EnclosingClass.ExclusiveRefinement != null &&
+ !Object.ReferenceEquals(
+ kv.Value.EnclosingClass.ExclusiveRefinement,
+ md.EnclosingClass)) {
+ sig.StaticMembers[kv.Key] = kv.Value;
+ }
+ resolved = true;
+ }
+ }
+ if (!resolved) {
sig.StaticMembers[kv.Key] = AmbiguousMemberDecl.Create(moduleDef, md, kv.Value);
+ }
} else {
// add new
sig.StaticMembers.Add(kv.Key, kv.Value);
}
- }
+ }
}
}
}
+
+ // second go through and overriding anything from the opened imports with the ones from the refinementBase
+ if (useImports && moduleDef.RefinementBaseSig != null) {
+ foreach (var kv in moduleDef.RefinementBaseSig.TopLevels) {
+ sig.TopLevels[kv.Key] = kv.Value;
+ }
+ foreach (var kv in moduleDef.RefinementBaseSig.StaticMembers) {
+ sig.StaticMembers[kv.Key] = kv.Value;
+ }
+ }
+
// This is solely used to detect duplicates amongst the various e
Dictionary<string, TopLevelDecl> toplevels = new Dictionary<string, TopLevelDecl>();
// Now add the things present
@@ -901,7 +1126,7 @@ namespace Microsoft.Dafny
Contract.Assert(d != null);
// register the class/datatype/module name
if (toplevels.ContainsKey(d.Name)) {
- Error(d, "Duplicate name of top-level declaration: {0}", d.Name);
+ reporter.Error(MessageSource.Resolver, d, "Duplicate name of top-level declaration: {0}", d.Name);
} else {
toplevels[d.Name] = d;
sig.TopLevels[d.Name] = d;
@@ -925,7 +1150,7 @@ namespace Microsoft.Dafny
// First, register the iterator's in- and out-parameters as readonly fields
foreach (var p in iter.Ins) {
if (members.ContainsKey(p.Name)) {
- Error(p, "Name of in-parameter is used by another member of the iterator: {0}", p.Name);
+ reporter.Error(MessageSource.Resolver, p, "Name of in-parameter is used by another member of the iterator: {0}", p.Name);
} else {
var field = new SpecialField(p.tok, p.Name, p.CompileName, "", "", p.IsGhost, false, false, p.Type, null);
field.EnclosingClass = iter; // resolve here
@@ -935,7 +1160,7 @@ namespace Microsoft.Dafny
}
foreach (var p in iter.Outs) {
if (members.ContainsKey(p.Name)) {
- Error(p, "Name of yield-parameter is used by another member of the iterator: {0}", p.Name);
+ reporter.Error(MessageSource.Resolver, p, "Name of yield-parameter is used by another member of the iterator: {0}", p.Name);
} else {
var field = new SpecialField(p.tok, p.Name, p.CompileName, "", "", p.IsGhost, true, true, p.Type, null);
field.EnclosingClass = iter; // resolve here
@@ -947,7 +1172,7 @@ namespace Microsoft.Dafny
foreach (var p in iter.Outs) {
var nm = p.Name + "s";
if (members.ContainsKey(nm)) {
- Error(p.tok, "Name of implicit yield-history variable '{0}' is already used by another member of the iterator", p.Name);
+ reporter.Error(MessageSource.Resolver, p.tok, "Name of implicit yield-history variable '{0}' is already used by another member of the iterator", p.Name);
} else {
var tp = new SeqType(p.Type.IsSubrangeType ? new IntType() : p.Type);
var field = new SpecialField(p.tok, nm, nm, "", "", true, true, false, tp, null);
@@ -961,9 +1186,9 @@ namespace Microsoft.Dafny
iter.Members.Add(f);
});
// add the additional special variables as fields
- iter.Member_Reads = new SpecialField(iter.tok, "_reads", "_reads", "", "", true, false, false, new SetType(new ObjectType()), null);
- iter.Member_Modifies = new SpecialField(iter.tok, "_modifies", "_modifies", "", "", true, false, false, new SetType(new ObjectType()), null);
- iter.Member_New = new SpecialField(iter.tok, "_new", "_new", "", "", true, true, true, new SetType(new ObjectType()), null);
+ iter.Member_Reads = new SpecialField(iter.tok, "_reads", "_reads", "", "", true, false, false, new SetType(true, new ObjectType()), null);
+ iter.Member_Modifies = new SpecialField(iter.tok, "_modifies", "_modifies", "", "", true, false, false, new SetType(true, new ObjectType()), null);
+ iter.Member_New = new SpecialField(iter.tok, "_new", "_new", "", "", true, true, true, new SetType(true, new ObjectType()), null);
foreach (var field in new List<Field>() { iter.Member_Reads, iter.Member_Modifies, iter.Member_New }) {
field.EnclosingClass = iter; // resolve here
members.Add(field.Name, field);
@@ -1019,7 +1244,7 @@ namespace Microsoft.Dafny
iter.Member_MoveNext = moveNext;
MemberDecl member;
if (members.TryGetValue(init.Name, out member)) {
- Error(member.tok, "member name '{0}' is already predefined for this iterator", init.Name);
+ reporter.Error(MessageSource.Resolver, member.tok, "member name '{0}' is already predefined for this iterator", init.Name);
} else {
members.Add(init.Name, init);
iter.Members.Add(init);
@@ -1027,13 +1252,13 @@ namespace Microsoft.Dafny
// If the name of the iterator is "Valid" or "MoveNext", one of the following will produce an error message. That
// error message may not be as clear as it could be, but the situation also seems unlikely to ever occur in practice.
if (members.TryGetValue("Valid", out member)) {
- Error(member.tok, "member name 'Valid' is already predefined for iterators");
+ reporter.Error(MessageSource.Resolver, member.tok, "member name 'Valid' is already predefined for iterators");
} else {
members.Add(valid.Name, valid);
iter.Members.Add(valid);
}
if (members.TryGetValue("MoveNext", out member)) {
- Error(member.tok, "member name 'MoveNext' is already predefined for iterators");
+ reporter.Error(MessageSource.Resolver, member.tok, "member name 'MoveNext' is already predefined for iterators");
} else {
members.Add(moveNext.Name, moveNext);
iter.Members.Add(moveNext);
@@ -1051,7 +1276,7 @@ namespace Microsoft.Dafny
members.Add(m.Name, m);
if (m is Constructor) {
if (cl is TraitDecl) {
- Error(m.tok, "a trait is not allowed to declare a constructor");
+ reporter.Error(MessageSource.Resolver, m.tok, "a trait is not allowed to declare a constructor");
} else {
cl.HasConstructor = true;
}
@@ -1107,9 +1332,9 @@ namespace Microsoft.Dafny
members.Add(extraName, extraMember);
}
} else if (m is Constructor && !((Constructor)m).HasName) {
- Error(m, "More than one anonymous constructor");
+ reporter.Error(MessageSource.Resolver, m, "More than one anonymous constructor");
} else {
- Error(m, "Duplicate member name: {0}", m.Name);
+ reporter.Error(MessageSource.Resolver, m, "Duplicate member name: {0}", m.Name);
}
}
if (cl.IsDefaultClass) {
@@ -1133,9 +1358,9 @@ namespace Microsoft.Dafny
foreach (DatatypeCtor ctor in dt.Ctors) {
if (ctor.Name.EndsWith("?")) {
- Error(ctor, "a datatype constructor name is not allowed to end with '?'");
+ reporter.Error(MessageSource.Resolver, ctor, "a datatype constructor name is not allowed to end with '?'");
} else if (ctors.ContainsKey(ctor.Name)) {
- Error(ctor, "Duplicate datatype constructor name: {0}", ctor.Name);
+ reporter.Error(MessageSource.Resolver, ctor, "Duplicate datatype constructor name: {0}", ctor.Name);
} else {
ctors.Add(ctor.Name, ctor);
@@ -1162,7 +1387,7 @@ namespace Microsoft.Dafny
foreach (var formal in ctor.Formals) {
bool nameError = false;
if (formal.HasName && members.ContainsKey(formal.Name)) {
- Error(ctor, "Name of deconstructor is used by another member of the datatype: {0}", formal.Name);
+ reporter.Error(MessageSource.Resolver, ctor, "Name of deconstructor is used by another member of the datatype: {0}", formal.Name);
nameError = true;
}
var dtor = new DatatypeDestructor(formal.tok, ctor, formal, formal.Name, "dtor_" + formal.CompileName, "", "", formal.IsGhost, formal.Type, null);
@@ -1179,15 +1404,17 @@ namespace Microsoft.Dafny
}
private ModuleSignature MakeAbstractSignature(ModuleSignature p, string Name, int Height, List<ModuleDefinition> mods) {
- var mod = new ModuleDefinition(Token.NoToken, Name + ".Abs", true, true, null, null, null, false);
+ var mod = new ModuleDefinition(Token.NoToken, Name + ".Abs", true, true, /*isExclusiveRefinement:*/ false, null, null, null, false);
+ mod.ClonedFrom = p.ModuleDef;
mod.Height = Height;
foreach (var kv in p.TopLevels) {
mod.TopLevelDecls.Add(CloneDeclaration(kv.Value, mod, mods, Name));
}
- var sig = RegisterTopLevelDecls(mod, false);
+ var sig = RegisterTopLevelDecls(mod, true);
sig.Refines = p.Refines;
sig.CompileSignature = p;
- sig.IsGhost = p.IsGhost;
+ sig.IsAbstract = p.IsAbstract;
+ sig.ExclusiveRefinement = p.ExclusiveRefinement;
mods.Add(mod);
ResolveModuleDefinition(mod, sig);
return sig;
@@ -1210,8 +1437,19 @@ namespace Microsoft.Dafny
}
- public static bool ResolvePath(ModuleDecl root, List<IToken> Path, out ModuleSignature p, ResolutionErrorReporter reporter) {
- Contract.Requires(reporter != null);
+ public static bool ResolvePath(ModuleDecl root, List<IToken> Path, out ModuleSignature p, ErrorReporter reporter) {
+ if (Path.Count == 1 && root is LiteralModuleDecl) {
+ // use the default export when the importing the root
+ LiteralModuleDecl decl = (LiteralModuleDecl)root;
+ p = decl.DefaultExport;
+ if (p == null) {
+ // no default view is specified.
+ reporter.Error(MessageSource.Resolver, decl.tok, "no default export declared in module: {0}", decl.Name);
+ return false;
+ }
+ return true;
+ }
+
p = root.Signature;
int i = 1;
while (i < Path.Count) {
@@ -1220,7 +1458,7 @@ namespace Microsoft.Dafny
p = pp;
i++;
} else {
- reporter.Error(Path[i], ModuleNotFoundErrorMessage(i, Path));
+ reporter.Error(MessageSource.Resolver, Path[i], ModuleNotFoundErrorMessage(i, Path));
break;
}
}
@@ -1241,6 +1479,14 @@ namespace Microsoft.Dafny
var typeRedirectionDependencies = new Graph<RedirectingTypeDecl>();
foreach (TopLevelDecl d in declarations) {
+ if (DafnyOptions.O.IronDafny && d.Module.IsExclusiveRefinement) {
+ var refinementOf =
+ def.RefinementBase.TopLevelDecls.Find(
+ i => String.Equals(i.Name, d.Name, StringComparison.InvariantCulture));
+ if (refinementOf != null && refinementOf.ExclusiveRefinement == null) {
+ refinementOf.ExclusiveRefinement = d;
+ }
+ }
Contract.Assert(d != null);
allTypeParameters.PushMarker();
ResolveTypeParameters(d.TypeArgs, true, d);
@@ -1271,11 +1517,15 @@ namespace Microsoft.Dafny
} else if (d is ModuleDecl) {
var decl = (ModuleDecl)d;
if (!def.IsAbstract) {
- if (decl.Signature.IsGhost)
+ if (decl.Signature.IsAbstract)
{
- if (!(def.IsDefaultModule)) // _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to
+ if (// _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to
// trusted verification, as toplevels can't be trusted if they invoke abstract module members.
- Error(d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one.");
+ !def.IsDefaultModule
+ // [IronDafny] it's possbile for an abstract module to have an exclusive refinement, so it no longer makes sense to disallow this.
+ && !DafnyOptions.O.IronDafny)
+
+ reporter.Error(MessageSource.Resolver, d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one.");
} else {
// physical modules are allowed everywhere
}
@@ -1301,16 +1551,7 @@ namespace Microsoft.Dafny
if (cycle != null) {
Contract.Assert(cycle.Count != 0);
var erste = cycle[0];
- Error(erste.Tok, "Cycle among redirecting types (newtypes, type synonyms): {0} -> {1}", Util.Comma(" -> ", cycle, syn => syn.Name), erste.Name);
- }
- }
-
- private readonly List<SetComprehension> needFiniteBoundsChecks_SetComprehension = new List<SetComprehension>();
- private readonly List<LetExpr> needFiniteBoundsChecks_LetSuchThatExpr = new List<LetExpr>();
- public int NFBC_Count {
- // provided just for the purpose of conveniently writing contracts for ResolveTopLevelDecl_Meat
- get {
- return needFiniteBoundsChecks_SetComprehension.Count + needFiniteBoundsChecks_LetSuchThatExpr.Count;
+ reporter.Error(MessageSource.Resolver, erste.Tok, "Cycle among redirecting types (newtypes, type synonyms): {0} -> {1}", Util.Comma(" -> ", cycle, syn => syn.Name), erste.Name);
}
}
@@ -1325,14 +1566,21 @@ namespace Microsoft.Dafny
new NativeType("long", Int64.MinValue, 0x8000000000000000, "L", false),
};
- public void ResolveTopLevelDecls_Meat(List<TopLevelDecl/*!*/>/*!*/ declarations, Graph<IndDatatypeDecl/*!*/>/*!*/ datatypeDependencies, Graph<CoDatatypeDecl/*!*/>/*!*/ codatatypeDependencies) {
+ public void ResolveTopLevelDecls_Core(List<TopLevelDecl/*!*/>/*!*/ declarations, Graph<IndDatatypeDecl/*!*/>/*!*/ datatypeDependencies, Graph<CoDatatypeDecl/*!*/>/*!*/ codatatypeDependencies) {
Contract.Requires(declarations != null);
Contract.Requires(cce.NonNullElements(datatypeDependencies));
Contract.Requires(cce.NonNullElements(codatatypeDependencies));
- Contract.Requires(NFBC_Count == 0);
- Contract.Ensures(NFBC_Count == 0);
+ Contract.Requires(AllTypeConstraints.Count == 0);
+ Contract.Ensures(AllTypeConstraints.Count == 0);
+
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
- int prevErrorCount = ErrorCount;
+ // ---------------------------------- Pass 0 ----------------------------------
+ // This pass resolves names, introduces (and may solve) type constraints, and
+ // builds the module's call graph.
+ // For 'newtype' declarations, it also checks that all types were fully
+ // determined.
+ // ----------------------------------------------------------------------------
// Resolve the meat of classes and iterators, the definitions of type synonyms, and the type parameters of all top-level type declarations
// First, resolve the newtype declarations and the constraint clauses, including filling in .ResolvedOp fields. This is needed for the
@@ -1347,7 +1595,7 @@ namespace Microsoft.Dafny
ResolveAttributes(d.Attributes, new ResolveOpts(new NoContext(d.Module), false));
// this check can be done only after it has been determined that the redirected types do not involve cycles
if (!dd.BaseType.IsNumericBased()) {
- Error(dd.tok, "newtypes must be based on some numeric type (got {0})", dd.BaseType);
+ reporter.Error(MessageSource.Resolver, dd.tok, "newtypes must be based on some numeric type (got {0})", dd.BaseType);
}
// type check the constraint, if any
if (dd.Var != null) {
@@ -1355,25 +1603,25 @@ namespace Microsoft.Dafny
Contract.Assert(dd.Constraint != null); // follows from NewtypeDecl invariant
scope.PushMarker();
var added = scope.Push(dd.Var.Name, dd.Var);
- Contract.Assert(added);
+ Contract.Assert(added == Scope<IVariable>.PushResult.Success);
ResolveType(dd.Var.tok, dd.Var.Type, dd, ResolveTypeOptionEnum.DontInfer, null);
- ResolveExpression(dd.Constraint, new ResolveOpts(dd, false, true));
+ ResolveExpression(dd.Constraint, new ResolveOpts(dd, false));
Contract.Assert(dd.Constraint.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(dd.Constraint.Type, Type.Bool)) {
- Error(dd.Constraint, "newtype constraint must be of type bool (instead got {0})", dd.Constraint.Type);
- }
+ ConstrainTypes(dd.Constraint.Type, Type.Bool, dd.Constraint, "newtype constraint must be of type bool (instead got {0})", dd.Constraint.Type);
+ SolveAllTypeConstraints();
if (!CheckTypeInference_Visitor.IsDetermined(dd.BaseType.NormalizeExpand())) {
- Error(dd.tok, "newtype's base type is not fully determined; add an explicit type for '{0}'", dd.Var.Name);
+ reporter.Error(MessageSource.Resolver, dd.tok, "newtype's base type is not fully determined; add an explicit type for '{0}'", dd.Var.Name);
}
- CheckTypeInference(dd.Constraint);
+ CheckTypeInference(dd.Constraint, dd);
scope.PopMarker();
}
}
}
// Now, we're ready for the other declarations.
foreach (TopLevelDecl d in declarations) {
+ Contract.Assert(AllTypeConstraints.Count == 0);
if (d is TraitDecl && d.TypeArgs.Count > 0) {
- Error(d, "sorry, traits with type parameters are not supported");
+ reporter.Error(MessageSource.Resolver, d, "sorry, traits with type parameters are not supported");
}
allTypeParameters.PushMarker();
ResolveTypeParameters(d.TypeArgs, false, d);
@@ -1392,156 +1640,86 @@ namespace Microsoft.Dafny
allTypeParameters.PopMarker();
}
- if (ErrorCount == prevErrorCount) {
- foreach (var e in needFiniteBoundsChecks_SetComprehension) {
- var missingBounds = new List<BoundVar>();
- CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds);
- if (missingBounds.Count != 0) {
- e.MissingBounds = missingBounds;
- foreach (var bv in e.MissingBounds) {
- Error(e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
- }
- }
- }
- foreach (var e in needFiniteBoundsChecks_LetSuchThatExpr) {
- Contract.Assert(!e.Exact); // only let-such-that expressions are ever added to the list
- Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully
- var constraint = e.RHSs[0];
- var missingBounds = new List<IVariable>();
- CheckTypeInference(constraint); // we need to resolve operators before the call to DiscoverBounds
- var allBounds = DiscoverBoundsAux(e.tok, new List<IVariable>(e.BoundVars), constraint, true, true, true, missingBounds);
- if (missingBounds.Count != 0) {
- e.Constraint_MissingBounds = missingBounds;
- foreach (var bv in e.Constraint_MissingBounds) {
- Error(e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
- }
- } else {
- e.Constraint_Bounds = new List<ComprehensionExpr.BoundedPool>();
- foreach (var pair in allBounds) {
- Contract.Assert(1 <= pair.Item2.Count);
- // TODO: The following could be improved by picking the bound that is most likely to give rise to an efficient compiled program
- e.Constraint_Bounds.Add(pair.Item2[0]);
- }
- }
- }
- }
- needFiniteBoundsChecks_SetComprehension.Clear();
- needFiniteBoundsChecks_LetSuchThatExpr.Clear();
+ // ---------------------------------- Pass 1 ----------------------------------
+ // This pass:
+ // * checks that type inference was able to determine all types
+ // * fills in the .ResolvedOp field of binary expressions
+ // * discovers bounds for:
+ // - forall statements
+ // - set comprehensions
+ // - map comprehensions
+ // - quantifier expressions
+ // - assign-such-that statements
+ // - compilable let-such-that expressions
+ // - newtype constraints
+ // For each statement body that it successfully typed, this pass also:
+ // * computes ghost interests
+ // * determines/checks tail-recursion.
+ // ----------------------------------------------------------------------------
Dictionary<string, NativeType> nativeTypeMap = new Dictionary<string, NativeType>();
foreach (var nativeType in NativeTypes) {
nativeTypeMap.Add(nativeType.Name, nativeType);
}
-
- if (ErrorCount == prevErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
// Check that type inference went well everywhere; this will also fill in the .ResolvedOp field in binary expressions
foreach (TopLevelDecl d in declarations) {
if (d is IteratorDecl) {
var iter = (IteratorDecl)d;
+ var prevErrCnt = reporter.Count(ErrorLevel.Error);
iter.Members.Iter(CheckTypeInference_Member);
+ if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {
+ iter.SubExpressions.Iter(e => CheckExpression(e, this, iter));
+ }
if (iter.Body != null) {
- CheckTypeInference(iter.Body);
+ CheckTypeInference(iter.Body, iter);
+ if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {
+ ComputeGhostInterest(iter.Body, false, iter);
+ CheckExpression(iter.Body, this, iter);
+ }
}
} else if (d is ClassDecl) {
var cl = (ClassDecl)d;
- cl.Members.Iter(CheckTypeInference_Member);
- } else if (d is NewtypeDecl) {
- var dd = (NewtypeDecl)d;
- bool? boolNativeType = null;
- NativeType stringNativeType = null;
- object nativeTypeAttr = true;
- bool hasNativeTypeAttr = Attributes.ContainsMatchingValue(dd.Attributes, "nativeType", ref nativeTypeAttr,
- new Attributes.MatchingValueOption[] {
- Attributes.MatchingValueOption.Empty,
- Attributes.MatchingValueOption.Bool,
- Attributes.MatchingValueOption.String },
- err => Error(dd, err));
- if (hasNativeTypeAttr) {
- if (nativeTypeAttr is bool) {
- boolNativeType = (bool)nativeTypeAttr;
- } else {
- string keyString = (string)nativeTypeAttr;
- if (nativeTypeMap.ContainsKey(keyString)) {
- stringNativeType = nativeTypeMap[keyString];
- } else {
- Error(dd, "Unsupported nativeType {0}", keyString);
+ foreach (var member in cl.Members) {
+ var prevErrCnt = reporter.Count(ErrorLevel.Error);
+ CheckTypeInference_Member(member);
+ if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {
+ if (member is Method) {
+ var m = (Method)member;
+ if (m.Body != null) {
+ ComputeGhostInterest(m.Body, m.IsGhost, m);
+ CheckExpression(m.Body, this, m);
+ DetermineTailRecursion(m);
+ }
+ } else if (member is Function) {
+ var f = (Function)member;
+ if (!f.IsGhost && f.Body != null) {
+ CheckIsCompilable(f.Body);
+ }
+ DetermineTailRecursion(f);
+ }
+ if (prevErrCnt == reporter.Count(ErrorLevel.Error) && member is ICodeContext) {
+ member.SubExpressions.Iter(e => CheckExpression(e, this, (ICodeContext)member));
}
}
}
- if (stringNativeType != null || boolNativeType == true) {
- if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) {
- Error(dd, "nativeType can only be used on integral types");
- }
- if (dd.Var == null) {
- Error(dd, "nativeType can only be used if newtype specifies a constraint");
- }
- }
+ } else if (d is NewtypeDecl) {
+ var dd = (NewtypeDecl)d;
if (dd.Var != null) {
Contract.Assert(dd.Constraint != null);
- CheckTypeInference(dd.Constraint);
-
- Func<Expression, BigInteger?> GetConst = null;
- GetConst = (Expression e) => {
- int m = 1;
- BinaryExpr bin = e as BinaryExpr;
- if (bin != null && bin.Op == BinaryExpr.Opcode.Sub && GetConst(bin.E0) == BigInteger.Zero) {
- m = -1;
- e = bin.E1;
- }
- LiteralExpr l = e as LiteralExpr;
- if (l != null && l.Value is BigInteger) {
- return m * (BigInteger)l.Value;
- }
- return null;
- };
- var missingBounds = new List<BoundVar>();
- var bounds = DiscoverBounds(dd.Constraint.tok, new List<BoundVar> { dd.Var }, dd.Constraint,
- true, true, missingBounds);
- List<NativeType> potentialNativeTypes =
- (stringNativeType != null) ? new List<NativeType> { stringNativeType } :
- (boolNativeType == false) ? new List<NativeType>() :
- NativeTypes;
- foreach (var nt in potentialNativeTypes) {
- if (missingBounds.Count == 0) {
- bool lowerOk = false;
- bool upperOk = false;
- foreach (var bound in bounds) {
- if (bound is ComprehensionExpr.IntBoundedPool) {
- var bnd = (ComprehensionExpr.IntBoundedPool)bound;
- if (bnd.LowerBound != null) {
- BigInteger? lower = GetConst(bnd.LowerBound);
- if (lower != null && nt.LowerBound <= lower) {
- lowerOk = true;
- }
- }
- if (bnd.UpperBound != null) {
- BigInteger? upper = GetConst(bnd.UpperBound);
- if (upper != null && upper <= nt.UpperBound) {
- upperOk = true;
- }
- }
- }
- }
- if (lowerOk && upperOk) {
- dd.NativeType = nt;
- break;
- }
- }
- }
- if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) {
- Error(dd, "Dafny's heuristics cannot find a compatible native type. " +
- "Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'");
- }
- if (dd.NativeType != null && stringNativeType == null) {
- ReportAdditionalInformation(dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}", dd.tok.val.Length);
- }
+ CheckExpression(dd.Constraint, this, dd);
}
+ FigureOutNativeType(dd, nativeTypeMap);
}
}
}
- if (ErrorCount == prevErrorCount) {
+
+ // ---------------------------------- Pass 2 ----------------------------------
+ // This pass fills in various additional information.
+ // ----------------------------------------------------------------------------
+
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
// fill in the postconditions and bodies of prefix lemmas
foreach (var com in ModuleDefinition.AllFixpointLemmas(declarations)) {
var prefixLemma = com.PrefixLemma;
@@ -1549,15 +1727,22 @@ namespace Microsoft.Dafny
continue; // something went wrong during registration of the prefix lemma (probably a duplicated fixpoint-lemma name)
}
var k = prefixLemma.Ins[0];
+ var focalPredicates = new HashSet<FixpointPredicate>();
if (com is CoLemma) {
// compute the postconditions of the prefix lemma
Contract.Assume(prefixLemma.Ens.Count == 0); // these are not supposed to have been filled in before
foreach (var p in com.Ens) {
var coConclusions = new HashSet<Expression>();
CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, coConclusions, true);
- var subst = new FixpointLemmaSpecificationSubstituter(coConclusions, new IdentifierExpr(k.tok, k.Name), this, true);
+ var subst = new FixpointLemmaSpecificationSubstituter(coConclusions, new IdentifierExpr(k.tok, k.Name), this.reporter, true);
var post = subst.CloneExpr(p.E);
prefixLemma.Ens.Add(new MaybeFreeExpression(post, p.IsFree));
+ foreach (var e in coConclusions) {
+ var fce = e as FunctionCallExpr;
+ if (fce != null) { // the other possibility is that "e" is a BinaryExpr
+ focalPredicates.Add((CoPredicate)fce.Function);
+ }
+ }
}
} else {
// compute the preconditions of the prefix lemma
@@ -1565,19 +1750,24 @@ namespace Microsoft.Dafny
foreach (var p in com.Req) {
var antecedents = new HashSet<Expression>();
CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, antecedents, false);
- var subst = new FixpointLemmaSpecificationSubstituter(antecedents, new IdentifierExpr(k.tok, k.Name), this, false);
+ var subst = new FixpointLemmaSpecificationSubstituter(antecedents, new IdentifierExpr(k.tok, k.Name), this.reporter, false);
var pre = subst.CloneExpr(p.E);
prefixLemma.Req.Add(new MaybeFreeExpression(pre, p.IsFree));
+ foreach (var e in antecedents) {
+ var fce = (FunctionCallExpr)e; // we expect "antecedents" to contain only FunctionCallExpr's
+ focalPredicates.Add((InductivePredicate)fce.Function);
+ }
}
}
+ reporter.Info(MessageSource.Resolver, com.tok, string.Format("{0} specialized for {1}", com.PrefixLemma.Name, Util.Comma(focalPredicates, p => p.Name)));
// Compute the statement body of the prefix lemma
Contract.Assume(prefixLemma.Body == null); // this is not supposed to have been filled in before
if (com.Body != null) {
var kMinusOne = new BinaryExpr(com.tok, BinaryExpr.Opcode.Sub, new IdentifierExpr(k.tok, k.Name), new LiteralExpr(com.tok, 1));
- var subst = new FixpointLemmaBodyCloner(com, kMinusOne, this);
+ var subst = new FixpointLemmaBodyCloner(com, kMinusOne, focalPredicates, this.reporter);
var mainBody = subst.CloneBlockStmt(com.Body);
var kPositive = new BinaryExpr(com.tok, BinaryExpr.Opcode.Lt, new LiteralExpr(com.tok, 0), new IdentifierExpr(k.tok, k.Name));
- var condBody = new IfStmt(com.BodyStartTok, mainBody.EndTok, kPositive, mainBody, null);
+ var condBody = new IfStmt(com.BodyStartTok, mainBody.EndTok, false, kPositive, mainBody, null);
prefixLemma.Body = new BlockStmt(com.tok, condBody.EndTok, new List<Statement>() { condBody });
}
// The prefix lemma now has all its components, so it's finally time we resolve it
@@ -1608,7 +1798,7 @@ namespace Microsoft.Dafny
}
}
- if (ErrorCount == prevErrorCount) { // because CheckCoCalls requires the given expression to have been successfully resolved
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // because CheckCoCalls requires the given expression to have been successfully resolved
// Perform the guardedness check on co-datatypes
foreach (var repr in ModuleDefinition.AllFunctionSCCs(declarations)) {
var module = repr.EnclosingModule;
@@ -1643,7 +1833,7 @@ namespace Microsoft.Dafny
foreach (var c in coCandidates) {
c.CandidateCall.CoCall = FunctionCallExpr.CoCallResolution.Yes;
c.EnclosingCoConstructor.IsCoCall = true;
- ReportAdditionalInformation(c.CandidateCall.tok, "co-recursive call", c.CandidateCall.Name.Length);
+ reporter.Info(MessageSource.Resolver, c.CandidateCall.tok, "co-recursive call");
}
// Finally, fill in the CoClusterTarget field
// Start by setting all the CoClusterTarget fields to CoRecursiveTargetAllTheWay.
@@ -1838,11 +2028,11 @@ namespace Microsoft.Dafny
// Check here for the presence of any 'ensures' clauses, which are not allowed (because we're not sure
// of their soundness)
if (fn.Ens.Count != 0) {
- Error(fn.Ens[0].tok, "a {0} is not allowed to declare any ensures clause", member.WhatKind);
+ reporter.Error(MessageSource.Resolver, fn.Ens[0].tok, "a {0} is not allowed to declare any ensures clause", member.WhatKind);
}
// Also check for 'reads' clauses
if (fn.Reads.Count != 0) {
- Error(fn.Reads[0].tok, "a {0} is not allowed to declare any reads clause", member.WhatKind); // (why?)
+ reporter.Error(MessageSource.Resolver, fn.Reads[0].tok, "a {0} is not allowed to declare any reads clause", member.WhatKind); // (why?)
}
if (fn.Body != null) {
FixpointPredicateChecks(fn.Body, fn, CallingPosition.Positive);
@@ -1858,13 +2048,229 @@ namespace Microsoft.Dafny
var dd = (NewtypeDecl)d;
if (dd.Module.CallGraph.GetSCCSize(dd) != 1) {
var cycle = Util.Comma(" -> ", dd.Module.CallGraph.GetSCC(dd), clbl => clbl.NameRelativeToModule);
- Error(dd.tok, "recursive dependency involving a newtype: " + cycle);
+ reporter.Error(MessageSource.Resolver, dd.tok, "recursive dependency involving a newtype: " + cycle);
}
}
}
}
}
+ private void FigureOutNativeType(NewtypeDecl dd, Dictionary<string, NativeType> nativeTypeMap) {
+ Contract.Requires(dd != null);
+ Contract.Requires(nativeTypeMap != null);
+ bool? boolNativeType = null;
+ NativeType stringNativeType = null;
+ object nativeTypeAttr = true;
+ bool hasNativeTypeAttr = Attributes.ContainsMatchingValue(dd.Attributes, "nativeType", ref nativeTypeAttr,
+ new Attributes.MatchingValueOption[] {
+ Attributes.MatchingValueOption.Empty,
+ Attributes.MatchingValueOption.Bool,
+ Attributes.MatchingValueOption.String },
+ err => reporter.Error(MessageSource.Resolver, dd, err));
+ if (hasNativeTypeAttr) {
+ if (nativeTypeAttr is bool) {
+ boolNativeType = (bool)nativeTypeAttr;
+ } else {
+ string keyString = (string)nativeTypeAttr;
+ if (nativeTypeMap.ContainsKey(keyString)) {
+ stringNativeType = nativeTypeMap[keyString];
+ } else {
+ reporter.Error(MessageSource.Resolver, dd, "Unsupported nativeType {0}", keyString);
+ }
+ }
+ }
+ if (stringNativeType != null || boolNativeType == true) {
+ if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) {
+ reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used on integral types");
+ }
+ if (dd.Var == null) {
+ reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used if newtype specifies a constraint");
+ }
+ }
+ if (dd.Var != null) {
+ Func<Expression, BigInteger?> GetConst = null;
+ GetConst = (Expression e) => {
+ int m = 1;
+ BinaryExpr bin = e as BinaryExpr;
+ if (bin != null && bin.Op == BinaryExpr.Opcode.Sub && GetConst(bin.E0) == BigInteger.Zero) {
+ m = -1;
+ e = bin.E1;
+ }
+ LiteralExpr l = e as LiteralExpr;
+ if (l != null && l.Value is BigInteger) {
+ return m * (BigInteger)l.Value;
+ }
+ return null;
+ };
+ var bounds = DiscoverAllBounds_SingleVar(dd.Var, dd.Constraint);
+ List<NativeType> potentialNativeTypes =
+ (stringNativeType != null) ? new List<NativeType> { stringNativeType } :
+ (boolNativeType == false) ? new List<NativeType>() :
+ NativeTypes;
+ foreach (var nt in potentialNativeTypes) {
+ bool lowerOk = false;
+ bool upperOk = false;
+ foreach (var bound in bounds) {
+ if (bound is ComprehensionExpr.IntBoundedPool) {
+ var bnd = (ComprehensionExpr.IntBoundedPool)bound;
+ if (bnd.LowerBound != null) {
+ BigInteger? lower = GetConst(bnd.LowerBound);
+ if (lower != null && nt.LowerBound <= lower) {
+ lowerOk = true;
+ }
+ }
+ if (bnd.UpperBound != null) {
+ BigInteger? upper = GetConst(bnd.UpperBound);
+ if (upper != null && upper <= nt.UpperBound) {
+ upperOk = true;
+ }
+ }
+ }
+ }
+ if (lowerOk && upperOk) {
+ dd.NativeType = nt;
+ break;
+ }
+ }
+ if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) {
+ reporter.Error(MessageSource.Resolver, dd, "Dafny's heuristics cannot find a compatible native type. " +
+ "Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'");
+ }
+ if (dd.NativeType != null && stringNativeType == null) {
+ reporter.Info(MessageSource.Resolver, dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be
+ /// untenable. If this is immediately known not to be untenable, false is returned.
+ /// </summary>
+ private bool ConstrainTypes(Type ty, Type expected, TopLevelDecl declForToken, string msg, params object[] args) {
+ Contract.Requires(ty != null);
+ Contract.Requires(expected != null);
+ Contract.Requires(declForToken != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(args != null);
+ return ConstrainTypes(ty, expected, declForToken.tok, msg, args);
+ }
+ /// <summary>
+ /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be
+ /// untenable. If this is immediately known not to be untenable, false is returned.
+ /// </summary>
+ private bool ConstrainTypes(Type ty, Type expected, MemberDecl declForToken, string msg, params object[] args) {
+ Contract.Requires(ty != null);
+ Contract.Requires(expected != null);
+ Contract.Requires(declForToken != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(args != null);
+ return ConstrainTypes(ty, expected, declForToken.tok, msg, args);
+ }
+ /// <summary>
+ /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be
+ /// untenable. If this is immediately known not to be untenable, false is returned.
+ /// </summary>
+ private bool ConstrainTypes(Type ty, Type expected, Statement stmtForToken, string msg, params object[] args) {
+ Contract.Requires(ty != null);
+ Contract.Requires(expected != null);
+ Contract.Requires(stmtForToken != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(args != null);
+ return ConstrainTypes(ty, expected, stmtForToken.Tok, msg, args);
+ }
+ /// <summary>
+ /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be
+ /// untenable. If this is immediately known not to be untenable, false is returned.
+ /// </summary>
+ private bool ConstrainTypes(Type ty, Type expected, Expression exprForToken, string msg, params object[] args) {
+ Contract.Requires(ty != null);
+ Contract.Requires(expected != null);
+ Contract.Requires(exprForToken != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(args != null);
+ return ConstrainTypes(ty, expected, exprForToken.tok, msg, args);
+ }
+ /// <summary>
+ /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be
+ /// untenable. If this is immediately known not to be untenable, false is returned.
+ /// </summary>
+ private bool ConstrainTypes(Type ty, Type expected, IToken tok, string msg, params object[] args) {
+ Contract.Requires(ty != null);
+ Contract.Requires(expected != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(args != null);
+#if LAZY_TYPE_CHECKING
+ var c = new TypeConstraint(ty, expected, tok, msg, args);
+ AllTypeConstraints.Add(c);
+ return true;
+#else
+ if (!UnifyTypes(ty, expected)) {
+ reporter.Error(MessageSource.Resolver, tok, msg, args);
+ return false;
+ }
+ return true;
+#endif
+ }
+
+ public List<TypeConstraint> AllTypeConstraints = new List<TypeConstraint>();
+
+ /// <summary>
+ /// Solves or simplifies as many type constraints as possible
+ /// </summary>
+ void PartiallySolveTypeConstraints() {
+ var remainingConstraints = new List<TypeConstraint>();
+ foreach (var constraint in AllTypeConstraints) {
+ if (!constraint.CheckTenable(this)) {
+ remainingConstraints.Add(constraint);
+ }
+ }
+ AllTypeConstraints = remainingConstraints;
+ }
+
+ /// <summary>
+ /// Attempts to fully solve all type constraints. Upon success, returns "true".
+ /// Upon failure, reports errors and returns "false".
+ /// Clears all constraints.
+ /// </summary>
+ bool SolveAllTypeConstraints() {
+ PartiallySolveTypeConstraints();
+ foreach (var constraint in AllTypeConstraints) {
+ constraint.ReportAsError(reporter);
+ }
+ var success = AllTypeConstraints.Count == 0;
+ AllTypeConstraints.Clear();
+ return success;
+ }
+
+ public class TypeConstraint
+ {
+ readonly Type Ty;
+ readonly Type Expected;
+ readonly IToken Tok;
+ readonly string Msg;
+ readonly object[] MsgArgs;
+ public TypeConstraint(Type ty, Type expected, IToken tok, string msg, object[] msgArgs) {
+ Ty = ty;
+ Expected = expected;
+ Tok = tok;
+ Msg = msg;
+ MsgArgs = msgArgs;
+ }
+ /// <summary>
+ /// Returns "true" if constraint is tenable, "false" otherwise.
+ /// </summary>
+ /// <returns></returns>
+ public bool CheckTenable(Resolver resolver) {
+ Contract.Requires(resolver != null);
+ return resolver.UnifyTypes(Ty, Expected);
+ }
+ public void ReportAsError(ErrorReporter reporter) {
+ Contract.Requires(reporter != null);
+ reporter.Error(MessageSource.Resolver, Tok, Msg, MsgArgs);
+ }
+ }
+
// ------------------------------------------------------------------------------------------------------
// ----- Visitors ---------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------
@@ -1876,45 +2282,14 @@ namespace Microsoft.Dafny
Contract.Requires(resolver != null);
this.resolver = resolver;
}
- public void Error(IToken tok, string msg, params object[] args) {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- Contract.Requires(args != null);
- resolver.Error(tok, msg, args);
- }
- public void Error(Expression expr, string msg, params object[] args) {
- Contract.Requires(expr != null);
- Contract.Requires(msg != null);
- Contract.Requires(args != null);
- Error(expr.tok, msg, args);
- }
}
abstract class ResolverTopDownVisitor<T> : TopDownVisitor<T>
{
- Resolver resolver;
+ protected Resolver resolver;
public ResolverTopDownVisitor(Resolver resolver) {
Contract.Requires(resolver != null);
this.resolver = resolver;
}
- protected void Error(IToken tok, string msg, params object[] args)
- {
- Contract.Requires(tok != null);
- Contract.Requires(msg != null);
- Contract.Requires(args != null);
- resolver.Error(tok, msg, args);
- }
- protected void Error(Expression expr, string msg, params object[] args)
- {
- Contract.Requires(expr != null);
- Contract.Requires(msg != null);
- Contract.Requires(args != null);
- Error(expr.tok, msg, args);
- }
- protected void ReportAdditionalInformation(IToken tok, string text, int length)
- {
- Contract.Requires(tok != null);
- resolver.ReportAdditionalInformation(tok, text, length);
- }
}
#endregion Visitors
@@ -1925,92 +2300,75 @@ namespace Microsoft.Dafny
private void CheckTypeInference_Member(MemberDecl member) {
if (member is Method) {
var m = (Method)member;
- m.Req.Iter(CheckTypeInference_MaybeFreeExpression);
- m.Ens.Iter(CheckTypeInference_MaybeFreeExpression);
- CheckTypeInference_Specification_FrameExpr(m.Mod);
- CheckTypeInference_Specification_Expr(m.Decreases);
+ m.Req.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m));
+ m.Ens.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m));
+ CheckTypeInference_Specification_FrameExpr(m.Mod, m);
+ CheckTypeInference_Specification_Expr(m.Decreases, m);
if (m.Body != null) {
- CheckTypeInference(m.Body);
- bool tail = true;
- bool hasTailRecursionPreference = Attributes.ContainsBool(m.Attributes, "tailrecursion", ref tail);
- if (hasTailRecursionPreference && !tail) {
- // the user specifically requested no tail recursion, so do nothing else
- } else if (hasTailRecursionPreference && tail && m.IsGhost) {
- Error(m.tok, "tail recursion can be specified only for methods that will be compiled, not for ghost methods");
- } else {
- var module = m.EnclosingClass.Module;
- var sccSize = module.CallGraph.GetSCCSize(m);
- if (hasTailRecursionPreference && 2 <= sccSize) {
- Error(m.tok, "sorry, tail-call optimizations are not supported for mutually recursive methods");
- } else if (hasTailRecursionPreference || sccSize == 1) {
- CallStmt tailCall = null;
- var status = CheckTailRecursive(m.Body.Body, m, ref tailCall, hasTailRecursionPreference);
- if (status != TailRecursionStatus.NotTailRecursive) {
- m.IsTailRecursive = true;
- if (tailCall != null) {
- // this means there was at least one recursive call
- ReportAdditionalInformation(m.tok, "tail recursive", m.Name.Length);
- }
- }
- }
- }
+ CheckTypeInference(m.Body, m);
}
} else if (member is Function) {
var f = (Function)member;
- var errorCount = ErrorCount;
- f.Req.Iter(CheckTypeInference);
- f.Ens.Iter(CheckTypeInference);
- f.Reads.Iter(fe => CheckTypeInference(fe.E));
- CheckTypeInference_Specification_Expr(f.Decreases);
+ var errorCount = reporter.Count(ErrorLevel.Error);
+ f.Req.Iter(e => CheckTypeInference(e, f));
+ f.Ens.Iter(e => CheckTypeInference(e, f));
+ f.Reads.Iter(fe => CheckTypeInference(fe.E, f));
+ CheckTypeInference_Specification_Expr(f.Decreases, f);
if (f.Body != null) {
- CheckTypeInference(f.Body);
- bool tail = true;
- if (Attributes.ContainsBool(f.Attributes, "tailrecursion", ref tail) && tail) {
- Error(f.tok, "sorry, tail-call functions are not supported");
- }
+ CheckTypeInference(f.Body, f);
}
- if (errorCount == ErrorCount && f is FixpointPredicate) {
+ if (errorCount == reporter.Count(ErrorLevel.Error) && f is FixpointPredicate) {
var cop = (FixpointPredicate)f;
CheckTypeInference_Member(cop.PrefixPredicate);
}
}
}
- private void CheckTypeInference_MaybeFreeExpression(MaybeFreeExpression mfe) {
+
+ private void CheckTypeInference_MaybeFreeExpression(MaybeFreeExpression mfe, ICodeContext codeContext) {
Contract.Requires(mfe != null);
+ Contract.Requires(codeContext != null);
foreach (var e in Attributes.SubExpressions(mfe.Attributes)) {
- CheckTypeInference(e);
+ CheckTypeInference(e, codeContext);
}
- CheckTypeInference(mfe.E);
+ CheckTypeInference(mfe.E, codeContext);
}
- private void CheckTypeInference_Specification_Expr(Specification<Expression> spec) {
+ private void CheckTypeInference_Specification_Expr(Specification<Expression> spec, ICodeContext codeContext) {
Contract.Requires(spec != null);
+ Contract.Requires(codeContext != null);
foreach (var e in Attributes.SubExpressions(spec.Attributes)) {
- CheckTypeInference(e);
+ CheckTypeInference(e, codeContext);
}
- spec.Expressions.Iter(CheckTypeInference);
+ spec.Expressions.Iter(e => CheckTypeInference(e, codeContext));
}
- private void CheckTypeInference_Specification_FrameExpr(Specification<FrameExpression> spec) {
+ private void CheckTypeInference_Specification_FrameExpr(Specification<FrameExpression> spec, ICodeContext codeContext) {
Contract.Requires(spec != null);
+ Contract.Requires(codeContext != null);
foreach (var e in Attributes.SubExpressions(spec.Attributes)) {
- CheckTypeInference(e);
+ CheckTypeInference(e, codeContext);
}
- spec.Expressions.Iter(fe => CheckTypeInference(fe.E));
+ spec.Expressions.Iter(fe => CheckTypeInference(fe.E, codeContext));
}
- void CheckTypeInference(Expression expr) {
+ void CheckTypeInference(Expression expr, ICodeContext codeContext) {
Contract.Requires(expr != null);
- var c = new CheckTypeInference_Visitor(this);
+ Contract.Requires(codeContext != null);
+ PartiallySolveTypeConstraints();
+ var c = new CheckTypeInference_Visitor(this, codeContext);
c.Visit(expr);
}
- void CheckTypeInference(Statement stmt) {
+ void CheckTypeInference(Statement stmt, ICodeContext codeContext) {
Contract.Requires(stmt != null);
- var c = new CheckTypeInference_Visitor(this);
+ Contract.Requires(codeContext != null);
+ var c = new CheckTypeInference_Visitor(this, codeContext);
c.Visit(stmt);
}
class CheckTypeInference_Visitor : ResolverBottomUpVisitor
{
- public CheckTypeInference_Visitor(Resolver resolver)
+ readonly ICodeContext codeContext;
+ public CheckTypeInference_Visitor(Resolver resolver, ICodeContext codeContext)
: base(resolver) {
Contract.Requires(resolver != null);
+ Contract.Requires(codeContext != null);
+ this.codeContext = codeContext;
}
protected override void VisitOneStmt(Statement stmt) {
if (stmt is VarDeclStmt) {
@@ -2018,28 +2376,109 @@ namespace Microsoft.Dafny
foreach (var local in s.Locals) {
CheckTypeIsDetermined(local.Tok, local.Type, "local variable");
}
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
+ s.BoundVars.Iter(bv => CheckTypeIsDetermined(bv.tok, bv.Type, "bound variable"));
+
} else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
s.BoundVars.Iter(bv => CheckTypeIsDetermined(bv.tok, bv.Type, "bound variable"));
+ List<BoundVar> missingBounds;
+ s.Bounds = DiscoverBestBounds_MultipleVars(s.BoundVars, s.Range, true, true, out missingBounds);
+
+ } else if (stmt is AssignSuchThatStmt) {
+ var s = (AssignSuchThatStmt)stmt;
+ if (s.AssumeToken == null) {
+ var varLhss = new List<IVariable>();
+ foreach (var lhs in s.Lhss) {
+ var ide = (IdentifierExpr)lhs.Resolved; // successful resolution implies all LHS's are IdentifierExpr's
+ varLhss.Add(ide.Var);
+ }
+ List<IVariable> missingBounds;
+ var bestBounds = DiscoverBestBounds_MultipleVars(varLhss, s.Expr, true, false, out missingBounds);
+ if (missingBounds.Count != 0) {
+ s.MissingBounds = missingBounds; // so that an error message can be produced during compilation
+ } else {
+ Contract.Assert(bestBounds != null);
+ s.Bounds = bestBounds;
+ }
+ }
+ } else if (stmt is CalcStmt) {
+ var s = (CalcStmt)stmt;
+ // The resolution of the calc statement builds up .Steps and .Result, which are of the form E0 OP E1, where
+ // E0 and E1 are expressions from .Lines. These additional expressions still need to have their .ResolvedOp
+ // fields filled in, so we visit them (but not their subexpressions) here.
+ foreach (var e in s.Steps) {
+ VisitOneExpr(e);
+ }
+ VisitOneExpr(s.Result);
}
}
protected override void VisitOneExpr(Expression expr) {
if (expr is ComprehensionExpr) {
var e = (ComprehensionExpr)expr;
- if (e != null) {
- foreach (var bv in e.BoundVars) {
- if (!IsDetermined(bv.Type.Normalize())) {
- Error(bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly",
- bv.Name);
+ foreach (var bv in e.BoundVars) {
+ if (!IsDetermined(bv.Type.Normalize())) {
+ resolver.reporter.Error(MessageSource.Resolver, bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", bv.Name);
+ }
+ }
+ // apply bounds discovery to quantifiers, finite sets, and finite maps
+ string what = null;
+ Expression whereToLookForBounds = null;
+ bool polarity = true;
+ if (e is QuantifierExpr) {
+ what = "quantifier";
+ whereToLookForBounds = ((QuantifierExpr)e).LogicalBody();
+ polarity = e is ExistsExpr;
+ } else if (e is SetComprehension) {
+ what = "set comprehension";
+ whereToLookForBounds = e.Range;
+ } else if (e is MapComprehension) {
+ what = "map comprehension";
+ whereToLookForBounds = e.Range;
+ } else {
+ Contract.Assume(e is LambdaExpr); // otherwise, unexpected ComprehensionExpr
+ }
+ if (whereToLookForBounds != null) {
+ List<BoundVar> missingBounds;
+ e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, whereToLookForBounds, polarity, true, out missingBounds);
+ if (missingBounds.Count != 0) {
+ e.MissingBounds = missingBounds;
+
+ if ((e is SetComprehension && !((SetComprehension)e).Finite) || (e is MapComprehension && !((MapComprehension)e).Finite)) {
+ // a possibly infinite set/map has no restrictions on its range (unless it's used in a compilable context, which is checked later)
+ } else if (e is QuantifierExpr) {
+ // a quantifier has no restrictions on its range (unless it's used in a compilable context, which is checked later)
+ } else if (e is SetComprehension && e.Type.HasFinitePossibleValues) {
+ // This means the set is finite, regardless of if the Range is bounded. So, we don't give any error here.
+ // However, if this expression is used in a non-ghost context (which is not yet known at this stage of
+ // resolution), the resolver will generate an error about that later.
+ } else {
+ // we cannot be sure that the set/map really is finite
+ foreach (var bv in missingBounds) {
+ resolver.reporter.Error(MessageSource.Resolver, e, "a {0} must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{1}'", what, bv.Name);
+ }
+ }
+ }
+ if (codeContext is Function && e.Bounds != null) {
+ // functions are not allowed to depend on the set of allocated objects
+ Contract.Assert(e.Bounds.Count == e.BoundVars.Count);
+ for (int i = 0; i < e.Bounds.Count; i++) {
+ var bound = e.Bounds[i] as ComprehensionExpr.RefBoundedPool;
+ if (bound != null) {
+ var bv = e.BoundVars[i];
+ resolver.reporter.Error(MessageSource.Resolver, expr, "a {0} involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{1}'", what, bv.Name);
+ }
}
}
}
+
} else if (expr is MemberSelectExpr) {
var e = (MemberSelectExpr)expr;
if (e.Member is Function || e.Member is Method) {
foreach (var p in e.TypeApplication) {
if (!IsDetermined(p.Normalize())) {
- Error(e.tok, "type '{0}' to the {2} '{1}' is not determined", p, e.Member.Name, e.Member.WhatKind);
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "type '{0}' to the {2} '{1}' is not determined", p, e.Member.Name, e.Member.WhatKind);
}
}
}
@@ -2047,8 +2486,8 @@ namespace Microsoft.Dafny
var e = (FunctionCallExpr)expr;
foreach (var p in e.TypeArgumentSubstitutions) {
if (!IsDetermined(p.Value.Normalize())) {
- Error(e.tok, "type variable '{0}' in the function call to '{1}' could not be determined{2}", p.Key.Name, e.Name,
- (e.Name.Contains("reveal_") || e.Name.Contains("_FULL"))
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "type variable '{0}' in the function call to '{1}' could not be determined{2}", p.Key.Name, e.Name,
+ (e.Name.StartsWith("reveal_") || e.Name.EndsWith("_FULL"))
? ". If you are making an opaque function, make sure that the function can be called."
: ""
);
@@ -2059,7 +2498,7 @@ namespace Microsoft.Dafny
foreach (var p in e.LHSs) {
foreach (var x in p.Vars) {
if (!IsDetermined(x.Type.Normalize())) {
- Error(e.tok, "the type of the bound variable '{0}' could not be determined", x.Name);
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "the type of the bound variable '{0}' could not be determined", x.Name);
}
}
}
@@ -2097,7 +2536,8 @@ namespace Microsoft.Dafny
proxy.T = new ObjectType();
return true;
}
- return !(t is TypeProxy); // all other proxies indicate the type has not yet been determined
+ // all other proxies indicate the type has not yet been determined, provided their type parameters have been
+ return !(t is TypeProxy) && t.TypeArgs.All(tt => IsDetermined(tt.Normalize()));
}
ISet<TypeProxy> UnderspecifiedTypeProxies = new HashSet<TypeProxy>();
bool CheckTypeIsDetermined(IToken tok, Type t, string what) {
@@ -2126,7 +2566,7 @@ namespace Microsoft.Dafny
var proxy = (TypeProxy)t;
if (!UnderspecifiedTypeProxies.Contains(proxy)) {
// report an error for this TypeProxy only once
- Error(tok, "the type of this {0} is underspecified", what);
+ resolver.reporter.Error(MessageSource.Resolver, tok, "the type of this {0} is underspecified", what);
UnderspecifiedTypeProxies.Add(proxy);
}
return false;
@@ -2147,6 +2587,58 @@ namespace Microsoft.Dafny
#endregion CheckTypeInference
// ------------------------------------------------------------------------------------------------------
+ // ----- CheckExpression --------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------------------------
+ #region CheckExpression
+ /// <summary>
+ /// This method computes ghost interests in the statement portion of StmtExpr's and
+ /// checks for hint restrictions in any CalcStmt.
+ /// </summary>
+ void CheckExpression(Expression expr, Resolver resolver, ICodeContext codeContext) {
+ Contract.Requires(expr != null);
+ Contract.Requires(resolver != null);
+ Contract.Requires(codeContext != null);
+ var v = new CheckExpression_Visitor(resolver, codeContext);
+ v.Visit(expr);
+ }
+ /// <summary>
+ /// This method computes ghost interests in the statement portion of StmtExpr's and
+ /// checks for hint restrictions in any CalcStmt.
+ /// </summary>
+ void CheckExpression(Statement stmt, Resolver resolver, ICodeContext codeContext) {
+ Contract.Requires(stmt != null);
+ Contract.Requires(resolver != null);
+ Contract.Requires(codeContext != null);
+ var v = new CheckExpression_Visitor(resolver, codeContext);
+ v.Visit(stmt);
+ }
+ class CheckExpression_Visitor : ResolverBottomUpVisitor
+ {
+ readonly ICodeContext CodeContext;
+ public CheckExpression_Visitor(Resolver resolver, ICodeContext codeContext)
+ : base(resolver) {
+ Contract.Requires(resolver != null);
+ Contract.Requires(codeContext != null);
+ CodeContext = codeContext;
+ }
+ protected override void VisitOneExpr(Expression expr) {
+ if (expr is StmtExpr) {
+ var e = (StmtExpr)expr;
+ resolver.ComputeGhostInterest(e.S, true, CodeContext);
+ }
+ }
+ protected override void VisitOneStmt(Statement stmt) {
+ if (stmt is CalcStmt) {
+ var s = (CalcStmt)stmt;
+ foreach (var h in s.Hints) {
+ resolver.CheckHintRestrictions(h, new HashSet<LocalVariable>());
+ }
+ }
+ }
+ }
+ #endregion
+
+ // ------------------------------------------------------------------------------------------------------
// ----- CheckTailRecursive -----------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------
#region CheckTailRecursive
@@ -2182,7 +2674,7 @@ namespace Microsoft.Dafny
if (status == TailRecursionStatus.TailCallSpent) {
// a tail call cannot be followed by non-ghost code
if (reportErrors) {
- Error(tailCall.Tok, "this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code");
+ reporter.Error(MessageSource.Resolver, tailCall.Tok, "this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code");
}
return TailRecursionStatus.NotTailRecursive;
}
@@ -2195,6 +2687,41 @@ namespace Microsoft.Dafny
return status;
}
+ void DetermineTailRecursion(Function f) {
+ Contract.Requires(f != null);
+ bool tail = true;
+ if (Attributes.ContainsBool(f.Attributes, "tailrecursion", ref tail) && tail) {
+ reporter.Error(MessageSource.Resolver, f.tok, "sorry, tail-call functions are not supported");
+ }
+ }
+
+ void DetermineTailRecursion(Method m) {
+ Contract.Requires(m != null);
+ bool tail = true;
+ bool hasTailRecursionPreference = Attributes.ContainsBool(m.Attributes, "tailrecursion", ref tail);
+ if (hasTailRecursionPreference && !tail) {
+ // the user specifically requested no tail recursion, so do nothing else
+ } else if (hasTailRecursionPreference && tail && m.IsGhost) {
+ reporter.Error(MessageSource.Resolver, m.tok, "tail recursion can be specified only for methods that will be compiled, not for ghost methods");
+ } else {
+ var module = m.EnclosingClass.Module;
+ var sccSize = module.CallGraph.GetSCCSize(m);
+ if (hasTailRecursionPreference && 2 <= sccSize) {
+ reporter.Error(MessageSource.Resolver, m.tok, "sorry, tail-call optimizations are not supported for mutually recursive methods");
+ } else if (hasTailRecursionPreference || sccSize == 1) {
+ CallStmt tailCall = null;
+ var status = CheckTailRecursive(m.Body.Body, m, ref tailCall, hasTailRecursionPreference);
+ if (status != TailRecursionStatus.NotTailRecursive) {
+ m.IsTailRecursive = true;
+ if (tailCall != null) {
+ // this means there was at least one recursive call
+ reporter.Info(MessageSource.Resolver, m.tok, "tail recursive");
+ }
+ }
+ }
+ }
+ }
+
/// <summary>
/// See CheckTailRecursive(List Statement, ...), including its description of "tailCall".
/// In the current implementation, "enclosingMethod" is not allowed to be a mutually recursive method.
@@ -2230,7 +2757,7 @@ namespace Microsoft.Dafny
// all is good
} else {
if (reportErrors) {
- Error(s.Tok, "the recursive call to '{0}' is not tail recursive because the actual out-parameter {1} is not the formal out-parameter '{2}'", s.Method.Name, i, formal.Name);
+ reporter.Error(MessageSource.Resolver, s.Tok, "the recursive call to '{0}' is not tail recursive because the actual out-parameter {1} is not the formal out-parameter '{2}'", s.Method.Name, i, formal.Name);
}
return TailRecursionStatus.NotTailRecursive;
}
@@ -2276,7 +2803,7 @@ namespace Microsoft.Dafny
if (status == TailRecursionStatus.NotTailRecursive) {
// an error has already been reported
} else if (reportErrors) {
- Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
+ reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
}
return TailRecursionStatus.NotTailRecursive;
}
@@ -2288,7 +2815,7 @@ namespace Microsoft.Dafny
if (status == TailRecursionStatus.NotTailRecursive) {
// an error has already been reported
} else if (reportErrors) {
- Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
+ reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
}
return TailRecursionStatus.NotTailRecursive;
}
@@ -2303,7 +2830,7 @@ namespace Microsoft.Dafny
if (status == TailRecursionStatus.NotTailRecursive) {
// an error has already been reported
} else if (reportErrors) {
- Error(tailCall.Tok, "a recursive call inside a forall statement is not a tail call");
+ reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a forall statement is not a tail call");
}
return TailRecursionStatus.NotTailRecursive;
}
@@ -2328,6 +2855,7 @@ namespace Microsoft.Dafny
if (s.Update != null) {
return CheckTailRecursive(s.Update, enclosingMethod, ref tailCall, reportErrors);
}
+ } else if (stmt is LetStmt) {
} else {
Contract.Assert(false); // unexpected statement type
}
@@ -2336,6 +2864,56 @@ namespace Microsoft.Dafny
#endregion CheckTailRecursive
// ------------------------------------------------------------------------------------------------------
+ // ----- FuelAdjustmentChecks ---------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------------------------
+ #region FuelAdjustmentChecks
+
+ protected void CheckForFuelAdjustments(IToken tok, Attributes attrs, ModuleDefinition currentModule) {
+ List<List<Expression>> results = Attributes.FindAllExpressions(attrs, "fuel");
+
+ if (results != null) {
+ foreach (List<Expression> args in results) {
+ if (args != null && args.Count >= 2) {
+ // Try to extract the function from the first argument
+ MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;
+ if (selectExpr != null) {
+ Function f = selectExpr.Member as Function;
+ if (f != null) {
+ f.IsFueled = true;
+ if (f.IsProtected && currentModule != f.EnclosingClass.Module) {
+ reporter.Error(MessageSource.Resolver, tok, "cannot adjust fuel for protected function {0} from another module", f.Name);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public class FuelAdjustment_Context
+ {
+ public ModuleDefinition currentModule;
+ public FuelAdjustment_Context(ModuleDefinition currentModule) {
+ this.currentModule = currentModule;
+ }
+ }
+
+ class FuelAdjustment_Visitor : ResolverTopDownVisitor<FuelAdjustment_Context>
+ {
+ public FuelAdjustment_Visitor(Resolver resolver)
+ : base(resolver) {
+ Contract.Requires(resolver != null);
+ }
+
+ protected override bool VisitOneStmt(Statement stmt, ref FuelAdjustment_Context st) {
+ resolver.CheckForFuelAdjustments(stmt.Tok, stmt.Attributes, st.currentModule);
+ return true;
+ }
+ }
+
+ #endregion FuelAdjustmentChecks
+
+ // ------------------------------------------------------------------------------------------------------
// ----- FixpointPredicateChecks ------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------
#region FixpointPredicateChecks
@@ -2409,6 +2987,7 @@ namespace Microsoft.Dafny
return false;
} else if (expr is QuantifierExpr) {
var e = (QuantifierExpr)expr;
+ Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution
var cpos = IsCoContext ? cp : Invert(cp);
if ((cpos == CallingPosition.Positive && e is ExistsExpr) || (cpos == CallingPosition.Negative && e is ForallExpr)) {
if (e.MissingBounds != null && e.MissingBounds.Count != 0) {
@@ -2450,7 +3029,7 @@ namespace Microsoft.Dafny
var article = context is InductivePredicate ? "an" : "a";
// we're looking at a recursive call
if (!(context is InductivePredicate ? e.Function is InductivePredicate : e.Function is CoPredicate)) {
- Error(e, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind);
+ resolver.reporter.Error(MessageSource.Resolver, e, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind);
} else if (cp != CallingPosition.Positive) {
var msg = string.Format("{0} {1} can be called recursively only in positive positions", article, context.WhatKind);
if (cp == CallingPosition.Neither) {
@@ -2459,10 +3038,10 @@ namespace Microsoft.Dafny
} else {
// the fixpoint-call is not inside an quantifier, so don't bother mentioning the part of existentials/universals in the error message
}
- Error(e, msg);
+ resolver.reporter.Error(MessageSource.Resolver, e, msg);
} else {
e.CoCall = FunctionCallExpr.CoCallResolution.Yes;
- ReportAdditionalInformation(e.tok, e.Function.Name + "#[_k - 1]", e.Function.Name.Length);
+ resolver.reporter.Info(MessageSource.Resolver, e.tok, e.Function.Name + "#[_k - 1]");
}
}
// do the sub-parts with cp := Neither
@@ -2477,7 +3056,7 @@ namespace Microsoft.Dafny
if (ModuleDefinition.InSameSCC(context, s.Method)) {
// we're looking at a recursive call
var article = context is InductivePredicate ? "an" : "a";
- Error(stmt.Tok, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind);
+ resolver.reporter.Error(MessageSource.Resolver, stmt.Tok, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind);
}
// do the sub-parts with the same "cp"
return true;
@@ -2518,7 +3097,7 @@ namespace Microsoft.Dafny
if (ModuleDefinition.InSameSCC(context, s.Method)) {
// we're looking at a recursive call (to a non-fixpoint-lemma)
var article = context is InductiveLemma ? "an" : "a";
- Error(s.Tok, "a recursive call from {0} {1} can go only to other {1}s and prefix lemmas", article, context.WhatKind);
+ resolver.reporter.Error(MessageSource.Resolver, s.Tok, "a recursive call from {0} {1} can go only to other {1}s and prefix lemmas", article, context.WhatKind);
}
}
}
@@ -2530,7 +3109,7 @@ namespace Microsoft.Dafny
// the call goes from a colemma context to a non-colemma callee
if (ModuleDefinition.InSameSCC(context, e.Function)) {
// we're looking at a recursive call (to a non-colemma)
- Error(e.tok, "a recursive call from a colemma can go only to other colemmas and prefix lemmas");
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "a recursive call from a colemma can go only to other colemmas and prefix lemmas");
}
}
}
@@ -2561,6 +3140,11 @@ namespace Microsoft.Dafny
foreach (var v in s.Locals) {
CheckEqualityTypes_Type(v.Tok, v.Type);
}
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
+ foreach (var v in s.BoundVars) {
+ CheckEqualityTypes_Type(v.Tok, v.Type);
+ }
} else if (stmt is WhileStmt) {
var s = (WhileStmt)stmt;
// don't recurse on the specification parts, which are ghost
@@ -2589,7 +3173,7 @@ namespace Microsoft.Dafny
foreach (var formalTypeArg in s.Method.TypeArgs) {
var actualTypeArg = s.MethodSelect.TypeArgumentSubstitutions()[formalTypeArg];
if (formalTypeArg.MustSupportEquality && !actualTypeArg.SupportsEquality) {
- Error(s.Tok, "type parameter {0} ({1}) passed to method {2} must support equality (got {3}){4}", i, formalTypeArg.Name, s.Method.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg));
+ resolver.reporter.Error(MessageSource.Resolver, s.Tok, "type parameter {0} ({1}) passed to method {2} must support equality (got {3}){4}", i, formalTypeArg.Name, s.Method.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg));
}
i++;
}
@@ -2617,6 +3201,14 @@ namespace Microsoft.Dafny
foreach (var v in s.BoundVars) {
CheckEqualityTypes_Type(v.Tok, v.Type);
}
+ // do substatements and subexpressions, except attributes and ensures clauses, since they are not compiled
+ foreach (var ss in s.SubStatements) {
+ Visit(ss, st);
+ }
+ if (s.Range != null) {
+ Visit(s.Range, st);
+ }
+ return false; // we're done
}
return true;
}
@@ -2636,9 +3228,9 @@ namespace Microsoft.Dafny
} else if (e1 != null && e1.Arguments.Count == 0) {
// oh yeah!
} else if (!t0.SupportsEquality) {
- Error(e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
+ resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
} else if (!t1.SupportsEquality) {
- Error(e.E1, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));
+ resolver.reporter.Error(MessageSource.Resolver, e.E1, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));
}
break;
default:
@@ -2651,12 +3243,12 @@ namespace Microsoft.Dafny
case BinaryExpr.ResolvedOpcode.Prefix:
case BinaryExpr.ResolvedOpcode.ProperPrefix:
if (!t1.SupportsEquality) {
- Error(e.E1, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));
+ resolver.reporter.Error(MessageSource.Resolver, e.E1, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));
} else if (!t0.SupportsEquality) {
if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InSet || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSeq) {
- Error(e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
+ resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
} else {
- Error(e.E0, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
+ resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));
}
}
break;
@@ -2675,6 +3267,18 @@ namespace Microsoft.Dafny
foreach (var bv in e.BoundVars) {
CheckEqualityTypes_Type(bv.tok, bv.Type);
}
+ } else if (expr is MemberSelectExpr) {
+ var e = (MemberSelectExpr)expr;
+ if (e.Member is Function || e.Member is Method) {
+ var i = 0;
+ foreach (var tp in ((ICallable)e.Member).TypeArgs) {
+ var actualTp = e.TypeApplication[e.Member.EnclosingClass.TypeArgs.Count + i];
+ if (tp.MustSupportEquality && !actualTp.SupportsEquality) {
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "type parameter {0} ({1}) passed to {5} '{2}' must support equality (got {3}){4}", i, tp.Name, e.Member.Name, actualTp, TypeEqualityErrorMessageHint(actualTp), e.Member.WhatKind);
+ }
+ i++;
+ }
+ }
} else if (expr is FunctionCallExpr) {
var e = (FunctionCallExpr)expr;
Contract.Assert(e.Function.TypeArgs.Count <= e.TypeArgumentSubstitutions.Count);
@@ -2682,7 +3286,7 @@ namespace Microsoft.Dafny
foreach (var formalTypeArg in e.Function.TypeArgs) {
var actualTypeArg = e.TypeArgumentSubstitutions[formalTypeArg];
if (formalTypeArg.MustSupportEquality && !actualTypeArg.SupportsEquality) {
- Error(e.tok, "type parameter {0} ({1}) passed to function {2} must support equality (got {3}){4}", i, formalTypeArg.Name, e.Function.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg));
+ resolver.reporter.Error(MessageSource.Resolver, e.tok, "type parameter {0} ({1}) passed to function {2} must support equality (got {3}){4}", i, formalTypeArg.Name, e.Function.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg));
}
i++;
}
@@ -2697,7 +3301,7 @@ namespace Microsoft.Dafny
i++;
}
return false; // we've done what there is to be done
- } else if (expr is SetDisplayExpr || expr is MultiSetDisplayExpr || expr is MapDisplayExpr || expr is MultiSetFormingExpr) {
+ } else if (expr is SetDisplayExpr || expr is MultiSetDisplayExpr || expr is MapDisplayExpr || expr is MultiSetFormingExpr || expr is StaticReceiverExpr) {
// This catches other expressions whose type may potentially be illegal
CheckEqualityTypes_Type(expr.tok, expr.Type);
}
@@ -2711,26 +3315,24 @@ namespace Microsoft.Dafny
if (type is BasicType) {
// fine
} else if (type is SetType) {
- var argType = ((SetType)type).Arg;
+ var st = (SetType)type;
+ var argType = st.Arg;
if (!argType.SupportsEquality) {
- Error(tok, "set argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType));
+ resolver.reporter.Error(MessageSource.Resolver, tok, "{2}set argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType), st.Finite ? "" : "i");
}
CheckEqualityTypes_Type(tok, argType);
} else if (type is MultiSetType) {
var argType = ((MultiSetType)type).Arg;
if (!argType.SupportsEquality) {
- Error(tok, "multiset argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType));
+ resolver.reporter.Error(MessageSource.Resolver, tok, "multiset argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType));
}
CheckEqualityTypes_Type(tok, argType);
} else if (type is MapType) {
var mt = (MapType)type;
- if (!mt.Finite) {
- Error(tok, "imaps do not support equality: {0}", mt);
- }
if (!mt.Domain.SupportsEquality) {
- Error(tok, "map domain type must support equality (got {0}){1}", mt.Domain, TypeEqualityErrorMessageHint(mt.Domain));
+ resolver.reporter.Error(MessageSource.Resolver, tok, "{2}map domain type must support equality (got {0}){1}", mt.Domain, TypeEqualityErrorMessageHint(mt.Domain), mt.Finite ? "" : "i");
}
CheckEqualityTypes_Type(tok, mt.Domain);
CheckEqualityTypes_Type(tok, mt.Range);
@@ -2756,7 +3358,7 @@ namespace Microsoft.Dafny
foreach (var argType in udt.TypeArgs) {
var formalTypeArg = formalTypeArgs[i];
if (formalTypeArg.MustSupportEquality && !argType.SupportsEquality) {
- Error(tok, "type parameter {0} ({1}) passed to type {2} must support equality (got {3}){4}", i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, TypeEqualityErrorMessageHint(argType));
+ resolver.reporter.Error(MessageSource.Resolver, tok, "type parameter {0} ({1}) passed to type {2} must support equality (got {3}){4}", i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, TypeEqualityErrorMessageHint(argType));
}
CheckEqualityTypes_Type(tok, argType);
i++;
@@ -2799,6 +3401,321 @@ namespace Microsoft.Dafny
#endregion CheckEqualityTypes
// ------------------------------------------------------------------------------------------------------
+ // ----- ComputeGhostInterest ---------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------------------------------
+ #region ComputeGhostInterest
+ public void ComputeGhostInterest(Statement stmt, bool mustBeErasable, ICodeContext codeContext) {
+ Contract.Requires(stmt != null);
+ Contract.Requires(codeContext != null);
+ var visitor = new GhostInterest_Visitor(codeContext, this);
+ visitor.Visit(stmt, mustBeErasable);
+ }
+ class GhostInterest_Visitor
+ {
+ readonly ICodeContext codeContext;
+ readonly Resolver resolver;
+ public GhostInterest_Visitor(ICodeContext codeContext, Resolver resolver) {
+ Contract.Requires(codeContext != null);
+ Contract.Requires(resolver != null);
+ this.codeContext = codeContext;
+ this.resolver = resolver;
+ }
+ protected void Error(Statement stmt, string msg, params object[] msgArgs) {
+ Contract.Requires(stmt != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(msgArgs != null);
+ resolver.reporter.Error(MessageSource.Resolver, stmt, msg, msgArgs);
+ }
+ protected void Error(Expression expr, string msg, params object[] msgArgs) {
+ Contract.Requires(expr != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(msgArgs != null);
+ resolver.reporter.Error(MessageSource.Resolver, expr, msg, msgArgs);
+ }
+ protected void Error(IToken tok, string msg, params object[] msgArgs) {
+ Contract.Requires(tok != null);
+ Contract.Requires(msg != null);
+ Contract.Requires(msgArgs != null);
+ resolver.reporter.Error(MessageSource.Resolver, tok, msg, msgArgs);
+ }
+ /// <summary>
+ /// This method does three things, in order:
+ /// 0. Sets .IsGhost to "true" if the statement is ghost. This often depends on some guard of the statement
+ /// (like the guard of an "if" statement) or the LHS of the statement (if it is an assignment).
+ /// Note, if "mustBeErasable", then the statement is already in a ghost context.
+ /// statement itself is ghost) or and the statement assigns to a non-ghost field
+ /// 1. Determines if the statement and all its subparts are legal under its computed .IsGhost setting.
+ /// 2. ``Upgrades'' .IsGhost to "true" if, after investigation of the substatements of the statement, it
+ /// turns out that the statement can be erased during compilation.
+ /// Notes:
+ /// * Both step (0) and step (2) sets the .IsGhost field. What step (0) does affects only the
+ /// rules of resolution, whereas step (2) makes a note for the later compilation phase.
+ /// * It is important to do step (0) before step (1)--that is, it is important to set the statement's ghost
+ /// status before descending into its sub-statements--because break statements look at the ghost status of
+ /// its enclosing statements.
+ /// * The method called by a StmtExpr must be ghost; however, this is checked elsewhere. For
+ /// this reason, it is not necessary to visit all subexpressions, unless the subexpression
+ /// matter for the ghost checking/recording of "stmt".
+ /// </summary>
+ public void Visit(Statement stmt, bool mustBeErasable) {
+ Contract.Requires(stmt != null);
+ Contract.Assume(!codeContext.IsGhost || mustBeErasable); // (this is really a precondition) codeContext.IsGhost ==> mustBeErasable
+
+ if (stmt is PredicateStmt) {
+ stmt.IsGhost = true;
+
+ } else if (stmt is PrintStmt) {
+ var s = (PrintStmt)stmt;
+ if (mustBeErasable) {
+ Error(stmt, "print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
+ } else {
+ s.Args.Iter(resolver.CheckIsCompilable);
+ }
+
+ } else if (stmt is BreakStmt) {
+ var s = (BreakStmt)stmt;
+ s.IsGhost = mustBeErasable;
+ if (s.IsGhost && !s.TargetStmt.IsGhost) {
+ var targetIsLoop = s.TargetStmt is WhileStmt || s.TargetStmt is AlternativeLoopStmt;
+ Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure"));
+ }
+
+ } else if (stmt is ProduceStmt) {
+ var s = (ProduceStmt)stmt;
+ var kind = stmt is YieldStmt ? "yield" : "return";
+ if (mustBeErasable && !codeContext.IsGhost) {
+ Error(stmt, "{0} statement is not allowed in this context (because it is guarded by a specification-only expression)", kind);
+ }
+ if (s.hiddenUpdate != null) {
+ Visit(s.hiddenUpdate, mustBeErasable);
+ }
+
+ } else if (stmt is AssignSuchThatStmt) {
+ var s = (AssignSuchThatStmt)stmt;
+ s.IsGhost = mustBeErasable || s.AssumeToken != null || s.Lhss.Any(AssignStmt.LhsIsToGhost);
+ if (mustBeErasable && !codeContext.IsGhost) {
+ foreach (var lhs in s.Lhss) {
+ var gk = AssignStmt.LhsIsToGhost_Which(lhs);
+ if (gk != AssignStmt.NonGhostKind.IsGhost) {
+ Error(lhs, "cannot assign to {0} in a ghost context", AssignStmt.NonGhostKind_To_String(gk));
+ }
+ }
+ } else if (!mustBeErasable && s.AssumeToken == null && resolver.UsesSpecFeatures(s.Expr)) {
+ foreach (var lhs in s.Lhss) {
+ var gk = AssignStmt.LhsIsToGhost_Which(lhs);
+ if (gk != AssignStmt.NonGhostKind.IsGhost) {
+ Error(lhs, "{0} cannot be assigned a value that depends on a ghost", AssignStmt.NonGhostKind_To_String(gk));
+ }
+ }
+ }
+
+ } else if (stmt is UpdateStmt) {
+ var s = (UpdateStmt)stmt;
+ s.ResolvedStatements.Iter(ss => Visit(ss, mustBeErasable));
+ s.IsGhost = s.ResolvedStatements.All(ss => ss.IsGhost);
+
+ } else if (stmt is VarDeclStmt) {
+ var s = (VarDeclStmt)stmt;
+ if (mustBeErasable) {
+ foreach (var local in s.Locals) {
+ // a local variable in a specification-only context might as well be ghost
+ local.IsGhost = true;
+ }
+ }
+ s.IsGhost = (s.Update == null || s.Update.IsGhost) && s.Locals.All(v => v.IsGhost);
+ if (s.Update != null) {
+ Visit(s.Update, mustBeErasable);
+ }
+
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
+ if (mustBeErasable) {
+ foreach (var bv in s.BoundVars) {
+ bv.IsGhost = true;
+ }
+ }
+ s.IsGhost = s.BoundVars.All(v => v.IsGhost);
+
+ } else if (stmt is AssignStmt) {
+ var s = (AssignStmt)stmt;
+ var lhs = s.Lhs.Resolved;
+ var gk = AssignStmt.LhsIsToGhost_Which(lhs);
+ if (gk == AssignStmt.NonGhostKind.IsGhost) {
+ s.IsGhost = true;
+ if (s.Rhs is TypeRhs) {
+ Error(s.Rhs.Tok, "'new' is not allowed in ghost contexts");
+ }
+ } else if (gk == AssignStmt.NonGhostKind.Variable && codeContext.IsGhost) {
+ // cool
+ } else if (mustBeErasable) {
+ Error(stmt, "Assignment to {0} is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)",
+ AssignStmt.NonGhostKind_To_String(gk));
+ } else if (s.Rhs is ExprRhs) {
+ var rhs = (ExprRhs)s.Rhs;
+ resolver.CheckIsCompilable(rhs.Expr);
+ } else if (s.Rhs is HavocRhs) {
+ // cool
+ } else {
+ var rhs = (TypeRhs)s.Rhs;
+ if (rhs.ArrayDimensions != null) {
+ foreach (var dim in rhs.ArrayDimensions) {
+ resolver.CheckIsCompilable(dim);
+ }
+ }
+ if (rhs.InitCall != null) {
+ foreach (var arg in rhs.InitCall.Args) {
+ resolver.CheckIsCompilable(arg);
+ }
+ }
+ }
+
+ } else if (stmt is CallStmt) {
+ var s = (CallStmt)stmt;
+ var callee = s.Method;
+ Contract.Assert(callee != null); // follows from the invariant of CallStmt
+ s.IsGhost = callee.IsGhost;
+ // check in-parameters
+ if (mustBeErasable) {
+ if (!s.IsGhost) {
+ Error(s, "only ghost methods can be called from this context");
+ }
+ } else {
+ resolver.CheckIsCompilable(s.Receiver);
+ int j;
+ if (!callee.IsGhost) {
+ j = 0;
+ foreach (var e in s.Args) {
+ Contract.Assume(j < callee.Ins.Count); // this should have already been checked by the resolver
+ if (!callee.Ins[j].IsGhost) {
+ resolver.CheckIsCompilable(e);
+ }
+ j++;
+ }
+ }
+ j = 0;
+ foreach (var e in s.Lhs) {
+ var resolvedLhs = e.Resolved;
+ if (callee.IsGhost || callee.Outs[j].IsGhost) {
+ // LHS must denote a ghost
+ if (resolvedLhs is IdentifierExpr) {
+ var ll = (IdentifierExpr)resolvedLhs;
+ if (!ll.Var.IsGhost) {
+ if (ll is AutoGhostIdentifierExpr && ll.Var is LocalVariable) {
+ // the variable was actually declared in this statement, so auto-declare it as ghost
+ ((LocalVariable)ll.Var).MakeGhost();
+ } else {
+ Error(s, "actual out-parameter {0} is required to be a ghost variable", j);
+ }
+ }
+ } else if (resolvedLhs is MemberSelectExpr) {
+ var ll = (MemberSelectExpr)resolvedLhs;
+ if (!ll.Member.IsGhost) {
+ Error(s, "actual out-parameter {0} is required to be a ghost field", j);
+ }
+ } else {
+ // this is an array update, and arrays are always non-ghost
+ Error(s, "actual out-parameter {0} is required to be a ghost variable", j);
+ }
+ }
+ j++;
+ }
+ }
+
+ } else if (stmt is BlockStmt) {
+ var s = (BlockStmt)stmt;
+ s.IsGhost = mustBeErasable; // set .IsGhost before descending into substatements (since substatements may do a 'break' out of this block)
+ s.Body.Iter(ss => Visit(ss, mustBeErasable));
+ s.IsGhost = s.IsGhost || s.Body.All(ss => ss.IsGhost); // mark the block statement as ghost if all its substatements are ghost
+
+ } else if (stmt is IfStmt) {
+ var s = (IfStmt)stmt;
+ s.IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard));
+ Visit(s.Thn, s.IsGhost);
+ if (s.Els != null) {
+ Visit(s.Els, s.IsGhost);
+ }
+ // if both branches were all ghost, then we can mark the enclosing statement as ghost as well
+ s.IsGhost = s.IsGhost || (s.Thn.IsGhost && (s.Els == null || s.Els.IsGhost));
+
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ s.IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard));
+ s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.IsGhost)));
+ s.IsGhost = s.IsGhost || s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost));
+
+ } else if (stmt is WhileStmt) {
+ var s = (WhileStmt)stmt;
+ s.IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard));
+ if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) {
+ Error(s, "'decreases *' is not allowed on ghost loops");
+ }
+ if (s.IsGhost && s.Mod.Expressions != null) {
+ s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);
+ }
+ if (s.Body != null) {
+ Visit(s.Body, s.IsGhost);
+ }
+ s.IsGhost = s.IsGhost || s.Body == null || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Body.IsGhost);
+
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ s.IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard));
+ if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) {
+ Error(s, "'decreases *' is not allowed on ghost loops");
+ }
+ if (s.IsGhost && s.Mod.Expressions != null) {
+ s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);
+ }
+ s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.IsGhost)));
+ s.IsGhost = s.IsGhost || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost)));
+
+ } else if (stmt is ForallStmt) {
+ var s = (ForallStmt)stmt;
+ s.IsGhost = mustBeErasable || s.Kind != ForallStmt.ParBodyKind.Assign || resolver.UsesSpecFeatures(s.Range);
+ if (s.Body != null) {
+ Visit(s.Body, s.IsGhost);
+ }
+ s.IsGhost = s.IsGhost || s.Body == null || s.Body.IsGhost;
+
+ } else if (stmt is ModifyStmt) {
+ var s = (ModifyStmt)stmt;
+ s.IsGhost = mustBeErasable;
+ if (s.IsGhost) {
+ s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);
+ }
+ if (s.Body != null) {
+ Visit(s.Body, mustBeErasable);
+ }
+
+ } else if (stmt is CalcStmt) {
+ var s = (CalcStmt)stmt;
+ s.IsGhost = true;
+ foreach (var h in s.Hints) {
+ Visit(h, true);
+ }
+
+ } else if (stmt is MatchStmt) {
+ var s = (MatchStmt)stmt;
+ s.IsGhost = mustBeErasable || resolver.UsesSpecFeatures(s.Source);
+ s.Cases.Iter(kase => kase.Body.Iter(ss => Visit(ss, s.IsGhost)));
+ s.IsGhost = s.IsGhost || s.Cases.All(kase => kase.Body.All(ss => ss.IsGhost));
+
+ } else if (stmt is SkeletonStatement) {
+ var s = (SkeletonStatement)stmt;
+ s.IsGhost = mustBeErasable;
+ if (s.S != null) {
+ Visit(s.S, mustBeErasable);
+ s.IsGhost = s.IsGhost || s.S.IsGhost;
+ }
+
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException();
+ }
+ }
+ }
+ #endregion
+
+ // ------------------------------------------------------------------------------------------------------
// ----- FillInDefaultLoopDecreases ---------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------
#region FillInDefaultLoopDecreases
@@ -2845,10 +3762,10 @@ namespace Microsoft.Dafny
for (int i = 0; i < cs.Method.Ins.Count; i++) {
argsSubstMap.Add(cs.Method.Ins[i], cs.Args[i]);
}
- var substituter = new Translator.AlphaConverting_Substituter(cs.Receiver, argsSubstMap, new Dictionary<TypeParameter, Type>(), new Translator());
+ var substituter = new Translator.AlphaConverting_Substituter(cs.Receiver, argsSubstMap, new Dictionary<TypeParameter, Type>(), new Translator(resolver.reporter));
foreach (var ens in cs.Method.Ens) {
var p = substituter.Substitute(ens.E); // substitute the call's actuals for the method's formals
- resolver.ReportAdditionalInformation(s.Tok, "ensures " + Printer.ExprToString(p) + ";", s.Tok.val.Length);
+ resolver.reporter.Info(MessageSource.Resolver, s.Tok, "ensures " + Printer.ExprToString(p));
}
}
}
@@ -2912,7 +3829,6 @@ namespace Microsoft.Dafny
readonly Scope<IVariable>/*!*/ scope = new Scope<IVariable>();
Scope<Statement>/*!*/ labeledStatements = new Scope<Statement>();
List<Statement> loopStack = new List<Statement>(); // the enclosing loops (from which it is possible to break out)
- readonly Dictionary<Statement, bool> inSpecOnlyContext = new Dictionary<Statement, bool>(); // invariant: domain contain union of the domains of "labeledStatements" and "loopStack"
/// <summary>
/// This method resolves the types that have been given after the 'extends' keyword. Then, it populates
@@ -2926,26 +3842,26 @@ namespace Microsoft.Dafny
currentClass = cl;
if (cl.TraitsTyp.Count > 0 && cl.TypeArgs.Count > 0) {
- Error(cl.tok, "sorry, traits are currently supported only for classes that take no type arguments"); // TODO: do the work to remove this limitation
+ reporter.Error(MessageSource.Resolver, cl.tok, "sorry, traits are currently supported only for classes that take no type arguments"); // TODO: do the work to remove this limitation
}
// Resolve names of traits extended
foreach (var tt in cl.TraitsTyp) {
- var prevErrorCount = ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
ResolveType(cl.tok, tt, new NoContext(cl.Module), ResolveTypeOptionEnum.DontInfer, null);
- if (ErrorCount == prevErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
var udt = tt as UserDefinedType;
if (udt != null && udt.ResolvedClass is TraitDecl) {
var trait = (TraitDecl)udt.ResolvedClass;
//disallowing inheritance in multi module case
if (cl.Module != trait.Module) {
- Error(udt.tok, "class '{0}' is in a different module than trait '{1}'. A class may only extend a trait in the same module.", cl.Name, trait.FullName);
+ reporter.Error(MessageSource.Resolver, udt.tok, "class '{0}' is in a different module than trait '{1}'. A class may only extend a trait in the same module.", cl.Name, trait.FullName);
} else {
// all is good
cl.TraitsObj.Add(trait);
}
} else {
- Error(udt != null ? udt.tok : cl.tok, "a class can only extend traits (found '{0}')", tt);
+ reporter.Error(MessageSource.Resolver, udt != null ? udt.tok : cl.tok, "a class can only extend traits (found '{0}')", tt);
}
}
}
@@ -2988,12 +3904,12 @@ namespace Microsoft.Dafny
} else if (member is Function) {
var f = (Function)member;
- var ec = ErrorCount;
+ var ec = reporter.Count(ErrorLevel.Error);
allTypeParameters.PushMarker();
ResolveTypeParameters(f.TypeArgs, true, f);
ResolveFunctionSignature(f);
allTypeParameters.PopMarker();
- if (f is FixpointPredicate && ec == ErrorCount) {
+ if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) {
var ff = ((FixpointPredicate)f).PrefixPredicate;
ff.EnclosingClass = cl;
allTypeParameters.PushMarker();
@@ -3004,13 +3920,13 @@ namespace Microsoft.Dafny
} else if (member is Method) {
var m = (Method)member;
- var ec = ErrorCount;
+ var ec = reporter.Count(ErrorLevel.Error);
allTypeParameters.PushMarker();
ResolveTypeParameters(m.TypeArgs, true, m);
ResolveMethodSignature(m);
allTypeParameters.PopMarker();
var com = m as FixpointLemma;
- if (com != null && com.PrefixLemma != null && ec == ErrorCount) {
+ if (com != null && com.PrefixLemma != null && ec == reporter.Count(ErrorLevel.Error)) {
var mm = com.PrefixLemma;
// resolve signature of the prefix lemma
mm.EnclosingClass = cl;
@@ -3031,7 +3947,7 @@ namespace Microsoft.Dafny
void InheritTraitMembers(ClassDecl cl) {
Contract.Requires(cl != null);
- var refinementTransformer = new RefinementTransformer(this, AdditionalInformationReporter, null);
+ var refinementTransformer = new RefinementTransformer(reporter);
//merging class members with parent members if any
var clMembers = classMembers[cl];
foreach (TraitDecl trait in cl.TraitsObj) {
@@ -3051,37 +3967,37 @@ namespace Microsoft.Dafny
} else if (traitMember is Function) {
var func = (Function)traitMember;
if (func.Body == null) {
- Error(cl.tok, "class '{0}' does not implement trait function '{1}.{2}'", cl.Name, trait.Name, traitMember.Name);
+ reporter.Error(MessageSource.Resolver, cl.tok, "class '{0}' does not implement trait function '{1}.{2}'", cl.Name, trait.Name, traitMember.Name);
} else if (!func.IsGhost && !func.IsStatic) {
cl.InheritedMembers.Add(func);
}
} else if (traitMember is Method) {
var method = (Method)traitMember;
if (method.Body == null) {
- Error(cl.tok, "class '{0}' does not implement trait method '{1}.{2}'", cl.Name, trait.Name, traitMember.Name);
+ reporter.Error(MessageSource.Resolver, cl.tok, "class '{0}' does not implement trait method '{1}.{2}'", cl.Name, trait.Name, traitMember.Name);
} else if (!method.IsGhost && !method.IsStatic) {
cl.InheritedMembers.Add(method);
}
}
} else if (clMember.EnclosingClass != cl) {
// The class inherits the member from two places
- Error(clMember.tok, "member name '{0}' in class '{1}' inherited from both traits '{2}' and '{3}'", traitMember.Name, cl.Name, clMember.EnclosingClass.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "member name '{0}' in class '{1}' inherited from both traits '{2}' and '{3}'", traitMember.Name, cl.Name, clMember.EnclosingClass.Name, trait.Name);
} else if (traitMember is Field) {
// The class is not allowed to do anything with the field other than silently inherit it.
if (clMember is Field) {
- Error(clMember.tok, "field '{0}' is inherited from trait '{1}' and is not allowed to be re-declared", traitMember.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "field '{0}' is inherited from trait '{1}' and is not allowed to be re-declared", traitMember.Name, trait.Name);
} else {
- Error(clMember.tok, "member name '{0}' in class '{1}' clashes with inherited field from trait '{2}'", traitMember.Name, cl.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "member name '{0}' in class '{1}' clashes with inherited field from trait '{2}'", traitMember.Name, cl.Name, trait.Name);
}
} else if (traitMember is Method) {
var traitMethod = (Method)traitMember;
if (traitMethod.Body != null) {
// The method was defined in the trait, so the class is not allowed to do anything with the method other than silently inherit it.
- Error(clMember.tok, "member '{0}' in class '{1}' overrides fully defined method inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "member '{0}' in class '{1}' overrides fully defined method inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name);
} else if (!(clMember is Method)) {
- Error(clMember.tok, "non-method member '{0}' overrides method '{1}' inherited from trait '{2}'", clMember.Name, traitMethod.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "non-method member '{0}' overrides method '{1}' inherited from trait '{2}'", clMember.Name, traitMethod.Name, trait.Name);
} else {
var classMethod = (Method)clMember;
classMethod.OverriddenMethod = traitMethod;
@@ -3093,7 +4009,7 @@ namespace Microsoft.Dafny
var traitMethodAllowsNonTermination = Contract.Exists(traitMethod.Decreases.Expressions, e => e is WildcardExpr);
var classMethodAllowsNonTermination = Contract.Exists(classMethod.Decreases.Expressions, e => e is WildcardExpr);
if (classMethodAllowsNonTermination && !traitMethodAllowsNonTermination) {
- Error(classMethod.tok, "not allowed to override a terminating method with a possibly non-terminating method ('{0}')", classMethod.Name);
+ reporter.Error(MessageSource.Resolver, classMethod.tok, "not allowed to override a terminating method with a possibly non-terminating method ('{0}')", classMethod.Name);
}
}
@@ -3101,9 +4017,9 @@ namespace Microsoft.Dafny
var traitFunction = (Function)traitMember;
if (traitFunction.Body != null) {
// The function was defined in the trait, so the class is not allowed to do anything with the function other than silently inherit it.
- Error(clMember.tok, "member '{0}' in class '{1}' overrides fully defined function inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "member '{0}' in class '{1}' overrides fully defined function inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name);
} else if (!(clMember is Function)) {
- Error(clMember.tok, "non-function member '{0}' overrides function '{1}' inherited from trait '{2}'", clMember.Name, traitFunction.Name, trait.Name);
+ reporter.Error(MessageSource.Resolver, clMember.tok, "non-function member '{0}' overrides function '{1}' inherited from trait '{2}'", clMember.Name, traitFunction.Name, trait.Name);
} else {
var classFunction = (Function)clMember;
classFunction.OverriddenFunction = traitFunction;
@@ -3136,12 +4052,12 @@ namespace Microsoft.Dafny
} else if (member is Function) {
var f = (Function)member;
- var ec = ErrorCount;
+ var ec = reporter.Count(ErrorLevel.Error);
allTypeParameters.PushMarker();
ResolveTypeParameters(f.TypeArgs, false, f);
ResolveFunction(f);
allTypeParameters.PopMarker();
- if (f is FixpointPredicate && ec == ErrorCount) {
+ if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) {
var ff = ((FixpointPredicate)f).PrefixPredicate;
allTypeParameters.PushMarker();
ResolveTypeParameters(ff.TypeArgs, false, ff);
@@ -3151,7 +4067,7 @@ namespace Microsoft.Dafny
} else if (member is Method) {
var m = (Method)member;
- var ec = ErrorCount;
+ var ec = reporter.Count(ErrorLevel.Error);
allTypeParameters.PushMarker();
ResolveTypeParameters(m.TypeArgs, false, m);
ResolveMethod(m);
@@ -3258,7 +4174,7 @@ namespace Microsoft.Dafny
// whatever is in scc-cleared now failed to pass the test
foreach (var dt in scc) {
if (dt.DefaultCtor == null) {
- Error(dt, "because of cyclic dependencies among constructor argument types, no instances of datatype '{0}' can be constructed", dt.Name);
+ reporter.Error(MessageSource.Resolver, dt, "because of cyclic dependencies among constructor argument types, no instances of datatype '{0}' can be constructed", dt.Name);
}
}
return;
@@ -3276,23 +4192,36 @@ namespace Microsoft.Dafny
Contract.Ensures(!Contract.Result<bool>() || dt.DefaultCtor != null);
// Stated differently, check that there is some constuctor where no argument type goes to the same stratum.
+ DatatypeCtor defaultCtor = null;
+ List<TypeParameter> lastTypeParametersUsed = null;
foreach (DatatypeCtor ctor in dt.Ctors) {
- var typeParametersUsed = new List<TypeParameter>();
+ List<TypeParameter> typeParametersUsed = new List<TypeParameter>();
foreach (Formal p in ctor.Formals) {
if (!CheckCanBeConstructed(p.Type, typeParametersUsed)) {
// the argument type (has a component which) is not yet known to be constructable
goto NEXT_OUTER_ITERATION;
}
}
- // this constructor satisfies the requirements, so the datatype is allowed
- dt.DefaultCtor = ctor;
+ // this constructor satisfies the requirements, check to see if it is a better fit than the
+ // one found so far. By "better" it means fewer type arguments. Between the ones with
+ // the same number of the type arguments, pick the one shows first.
+ if (defaultCtor == null || typeParametersUsed.Count < lastTypeParametersUsed.Count) {
+ defaultCtor = ctor;
+ lastTypeParametersUsed = typeParametersUsed;
+ }
+
+ NEXT_OUTER_ITERATION: { }
+ }
+
+ if (defaultCtor != null) {
+ dt.DefaultCtor = defaultCtor;
dt.TypeParametersUsedInConstructionByDefaultCtor = new bool[dt.TypeArgs.Count];
for (int i = 0; i < dt.TypeArgs.Count; i++) {
- dt.TypeParametersUsedInConstructionByDefaultCtor[i] = typeParametersUsed.Contains(dt.TypeArgs[i]);
+ dt.TypeParametersUsedInConstructionByDefaultCtor[i] = lastTypeParametersUsed.Contains(dt.TypeArgs[i]);
}
return true;
- NEXT_OUTER_ITERATION: { }
}
+
// no constructor satisfied the requirements, so this is an illegal datatype declaration
return false;
}
@@ -3339,7 +4268,8 @@ namespace Microsoft.Dafny
(anotherIndDt != null && anotherIndDt.EqualitySupport == IndDatatypeDecl.ES.Never) ||
arg.Type.IsCoDatatype ||
arg.Type.IsArrowType ||
- arg.Type.IsIMapType) {
+ arg.Type.IsIMapType ||
+ arg.Type.IsISetType) {
// arg.Type is known never to support equality
// So, go around the entire SCC and record what we learnt
foreach (var ddtt in scc) {
@@ -3422,26 +4352,17 @@ namespace Microsoft.Dafny
void ResolveAttributes(Attributes attrs, ResolveOpts opts) {
Contract.Requires(opts != null);
- Contract.Requires(opts.DontCareAboutCompilation); // attributes are never compiled
// order does not matter much for resolution, so resolve them in reverse order
- for (; attrs != null; attrs = attrs.Prev) {
- if (attrs.Args != null) {
- ResolveAttributeArgs(attrs.Args, opts, true);
- }
- }
- }
-
- void ResolveAttributeArgs(List<Expression> args, ResolveOpts opts, bool allowGhosts) {
- Contract.Requires(args != null);
- foreach (var arg in args) {
- Contract.Assert(arg != null);
- int prevErrors = ErrorCount;
- ResolveExpression(arg, opts);
- if (!allowGhosts) {
- CheckIsNonGhost(arg);
- }
- if (prevErrors == ErrorCount) {
- CheckTypeInference(arg);
+ foreach (var attr in attrs.AsEnumerable()) {
+ if (attr.Args != null) {
+ foreach (var arg in attr.Args) {
+ Contract.Assert(arg != null);
+ int prevErrors = reporter.Count(ErrorLevel.Error);
+ ResolveExpression(arg, opts);
+ if (prevErrors == reporter.Count(ErrorLevel.Error)) {
+ CheckTypeInference(arg, opts.codeContext);
+ }
+ }
}
}
}
@@ -3457,12 +4378,43 @@ namespace Microsoft.Dafny
tp.Parent = parent;
tp.PositionalIndex = index;
}
- if (!allTypeParameters.Push(tp.Name, tp) && emitErrors) {
- Error(tp, "Duplicate type-parameter name: {0}", tp.Name);
+ var r = allTypeParameters.Push(tp.Name, tp);
+ if (emitErrors) {
+ if (r == Scope<TypeParameter>.PushResult.Duplicate) {
+ reporter.Error(MessageSource.Resolver, tp, "Duplicate type-parameter name: {0}", tp.Name);
+ } else if (r == Scope<TypeParameter>.PushResult.Shadow) {
+ reporter.Warning(MessageSource.Resolver, tp.tok, "Shadowed type-parameter name: {0}", tp.Name);
+ }
}
}
}
+ void ScopePushAndReport(Scope<IVariable> scope, IVariable v, string kind) {
+ Contract.Requires(scope != null);
+ Contract.Requires(v != null);
+ Contract.Requires(kind != null);
+ ScopePushAndReport(scope, v.Name, v, v.Tok, kind);
+ }
+
+ void ScopePushAndReport<Thing>(Scope<Thing> scope, string name, Thing thing, IToken tok, string kind) where Thing : class {
+ Contract.Requires(scope != null);
+ Contract.Requires(name != null);
+ Contract.Requires(thing != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(kind != null);
+ var r = scope.Push(name, thing);
+ switch (r) {
+ case Scope<Thing>.PushResult.Success:
+ break;
+ case Scope<Thing>.PushResult.Duplicate:
+ reporter.Error(MessageSource.Resolver, tok, "Duplicate {0} name: {1}", kind, name);
+ break;
+ case Scope<Thing>.PushResult.Shadow:
+ reporter.Warning(MessageSource.Resolver, tok, "Shadowed {0} name: {1}", kind, name);
+ break;
+ }
+ }
+
/// <summary>
/// Assumes type parameters have already been pushed
/// </summary>
@@ -3470,13 +4422,11 @@ namespace Microsoft.Dafny
Contract.Requires(f != null);
scope.PushMarker();
if (f.SignatureIsOmitted) {
- Error(f, "function signature can be omitted only in refining functions");
+ reporter.Error(MessageSource.Resolver, f, "function signature can be omitted only in refining functions");
}
var option = f.TypeArgs.Count == 0 ? new ResolveTypeOption(f) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);
foreach (Formal p in f.Formals) {
- if (!scope.Push(p.Name, p)) {
- Error(p, "Duplicate parameter name: {0}", p.Name);
- }
+ ScopePushAndReport(scope, p, "parameter");
ResolveType(p.tok, p.Type, f, option, f.TypeArgs);
}
ResolveType(f.tok, f.ResultType, f, option, f.TypeArgs);
@@ -3495,39 +4445,32 @@ namespace Microsoft.Dafny
foreach (Formal p in f.Formals) {
scope.Push(p.Name, p);
}
- ResolveAttributes(f.Attributes, new ResolveOpts(f, false, true));
+ ResolveAttributes(f.Attributes, new ResolveOpts(f, false));
foreach (Expression r in f.Req) {
- ResolveExpression(r, new ResolveOpts(f, false, true));
+ ResolveExpression(r, new ResolveOpts(f, false));
Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(r.Type, Type.Bool)) {
- Error(r, "Precondition must be a boolean (got {0})", r.Type);
- }
+ ConstrainTypes(r.Type, Type.Bool, r, "Precondition must be a boolean (got {0})", r.Type);
}
foreach (FrameExpression fr in f.Reads) {
- ResolveFrameExpression(fr, true, f.IsGhost, f);
+ ResolveFrameExpression(fr, true, f);
}
foreach (Expression r in f.Ens) {
- ResolveExpression(r, new ResolveOpts(f, false, true)); // since this is a function, the postcondition is still a one-state predicate
+ ResolveExpression(r, new ResolveOpts(f, false)); // since this is a function, the postcondition is still a one-state predicate
Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(r.Type, Type.Bool)) {
- Error(r, "Postcondition must be a boolean (got {0})", r.Type);
- }
+ ConstrainTypes(r.Type, Type.Bool, r, "Postcondition must be a boolean (got {0})", r.Type);
}
- ResolveAttributes(f.Decreases.Attributes, new ResolveOpts(f, false, true));
+ ResolveAttributes(f.Decreases.Attributes, new ResolveOpts(f, false));
foreach (Expression r in f.Decreases.Expressions) {
- ResolveExpression(r, new ResolveOpts(f, false, true));
+ ResolveExpression(r, new ResolveOpts(f, false));
// any type is fine
}
+ SolveAllTypeConstraints();
if (f.Body != null) {
- var prevErrorCount = ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
ResolveExpression(f.Body, new ResolveOpts(f, false));
- if (!f.IsGhost && prevErrorCount == ErrorCount) {
- CheckIsNonGhost(f.Body);
- }
+ SolveAllTypeConstraints();
Contract.Assert(f.Body.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(f.Body.Type, f.ResultType)) {
- Error(f, "Function body type mismatch (expected {0}, got {1})", f.ResultType, f.Body.Type);
- }
+ ConstrainTypes(f.Body.Type, f.ResultType, f, "Function body type mismatch (expected {0}, got {1})", f.ResultType, f.Body.Type);
}
scope.PopMarker();
}
@@ -3535,14 +4478,11 @@ namespace Microsoft.Dafny
/// <summary>
///
/// </summary>
- /// <param name="fe"></param>
/// <param name="readsFrame">True indicates "reads", false indicates "modifies".</param>
- /// <param name="isGhostContext"></param>
- /// <param name="codeContext"></param>
- void ResolveFrameExpression(FrameExpression fe, bool readsFrame, bool isGhostContext, ICodeContext codeContext) {
+ void ResolveFrameExpression(FrameExpression fe, bool readsFrame, ICodeContext codeContext) {
Contract.Requires(fe != null);
Contract.Requires(codeContext != null);
- ResolveExpression(fe.E, new ResolveOpts(codeContext, false, true /* yes, this is ghost */));
+ ResolveExpression(fe.E, new ResolveOpts(codeContext, false));
Type t = fe.E.Type;
Contract.Assert(t != null); // follows from postcondition of ResolveExpression
var arrTy = t.AsArrowType;
@@ -3553,8 +4493,7 @@ namespace Microsoft.Dafny
if (collType != null) {
t = collType.Arg;
}
- if (!UnifyTypes(t, new ObjectType())) {
- Error(fe.E, "a {0}-clause expression must denote an object or a collection of objects (instead got {1})", readsFrame ? "reads" : "modifies", fe.E.Type);
+ if (!ConstrainTypes(t, new ObjectType(), fe.E, "a {0}-clause expression must denote an object or a collection of objects (instead got {1})", readsFrame ? "reads" : "modifies", fe.E.Type)) {
} else if (fe.FieldName != null) {
NonProxyType nptype;
MemberDecl member = ResolveMember(fe.E.tok, t, fe.FieldName, out nptype);
@@ -3562,9 +4501,7 @@ namespace Microsoft.Dafny
if (member == null) {
// error has already been reported by ResolveMember
} else if (!(member is Field)) {
- Error(fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, ctype.Name);
- } else if (!readsFrame && isGhostContext && !member.IsGhost) {
- Error(fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName);
+ reporter.Error(MessageSource.Resolver, fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, ctype.Name);
} else {
Contract.Assert(ctype != null && ctype.ResolvedClass != null); // follows from postcondition of ResolveMember
fe.Field = (Field)member;
@@ -3573,27 +4510,34 @@ namespace Microsoft.Dafny
}
/// <summary>
+ /// This method can be called even if the resolution of "fe" failed; in that case, this method will
+ /// not issue any error message.
+ /// </summary>
+ void DisallowNonGhostFieldSpecifiers(FrameExpression fe) {
+ Contract.Requires(fe != null);
+ if (fe.Field != null && !fe.Field.IsGhost) {
+ reporter.Error(MessageSource.Resolver, fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName);
+ }
+ }
+
+ /// <summary>
/// Assumes type parameters have already been pushed
/// </summary>
void ResolveMethodSignature(Method m) {
Contract.Requires(m != null);
scope.PushMarker();
if (m.SignatureIsOmitted) {
- Error(m, "method signature can be omitted only in refining methods");
+ reporter.Error(MessageSource.Resolver, m, "method signature can be omitted only in refining methods");
}
var option = m.TypeArgs.Count == 0 ? new ResolveTypeOption(m) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);
// resolve in-parameters
foreach (Formal p in m.Ins) {
- if (!scope.Push(p.Name, p)) {
- Error(p, "Duplicate parameter name: {0}", p.Name);
- }
+ ScopePushAndReport(scope, p, "parameter");
ResolveType(p.tok, p.Type, m, option, m.TypeArgs);
}
// resolve out-parameters
foreach (Formal p in m.Outs) {
- if (!scope.Push(p.Name, p)) {
- Error(p, "Duplicate parameter name: {0}", p.Name);
- }
+ ScopePushAndReport(scope, p, "parameter");
ResolveType(p.tok, p.Type, m, option, m.TypeArgs);
}
scope.PopMarker();
@@ -3620,34 +4564,31 @@ namespace Microsoft.Dafny
// Start resolving specification...
foreach (MaybeFreeExpression e in m.Req) {
- ResolveAttributes(e.Attributes, new ResolveOpts(m, false, true));
- ResolveExpression(e.E, new ResolveOpts(m, false, true));
+ ResolveAttributes(e.Attributes, new ResolveOpts(m, false));
+ ResolveExpression(e.E, new ResolveOpts(m, false));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Precondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Precondition must be a boolean (got {0})", e.E.Type);
}
- ResolveAttributes(m.Mod.Attributes, new ResolveOpts(m, false, true));
+ ResolveAttributes(m.Mod.Attributes, new ResolveOpts(m, false));
foreach (FrameExpression fe in m.Mod.Expressions) {
- ResolveFrameExpression(fe, false, m.IsGhost, m);
+ ResolveFrameExpression(fe, false, m);
if (m is Lemma || m is FixpointLemma) {
- Error(fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind);
+ reporter.Error(MessageSource.Resolver, fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind);
+ } else if (m.IsGhost) {
+ DisallowNonGhostFieldSpecifiers(fe);
}
}
- ResolveAttributes(m.Decreases.Attributes, new ResolveOpts(m, false, true));
+ ResolveAttributes(m.Decreases.Attributes, new ResolveOpts(m, false));
foreach (Expression e in m.Decreases.Expressions) {
- ResolveExpression(e, new ResolveOpts(m, false, true));
+ ResolveExpression(e, new ResolveOpts(m, false));
// any type is fine
- if (m.IsGhost && e is WildcardExpr) {
- Error(e, "'decreases *' is not allowed on ghost methods");
- }
}
// Add out-parameters to a new scope that will also include the outermost-level locals of the body
// Don't care about any duplication errors among the out-parameters, since they have already been reported
scope.PushMarker();
if (m is FixpointLemma && m.Outs.Count != 0) {
- Error(m.Outs[0].tok, "{0}s are not allowed to have out-parameters", m.WhatKind);
+ reporter.Error(MessageSource.Resolver, m.Outs[0].tok, "{0}s are not allowed to have out-parameters", m.WhatKind);
} else {
foreach (Formal p in m.Outs) {
scope.Push(p.Name, p);
@@ -3656,13 +4597,12 @@ namespace Microsoft.Dafny
// ... continue resolving specification
foreach (MaybeFreeExpression e in m.Ens) {
- ResolveAttributes(e.Attributes, new ResolveOpts(m, true, true));
- ResolveExpression(e.E, new ResolveOpts(m, true, true));
+ ResolveAttributes(e.Attributes, new ResolveOpts(m, true));
+ ResolveExpression(e.E, new ResolveOpts(m, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Postcondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Postcondition must be a boolean (got {0})", e.E.Type);
}
+ SolveAllTypeConstraints();
// Resolve body
if (m.Body != null) {
@@ -3673,12 +4613,12 @@ namespace Microsoft.Dafny
var k = com.PrefixLemma.Ins[0];
scope.Push(k.Name, k); // we expect no name conflict for _k
}
- var codeContext = m;
- ResolveBlockStatement(m.Body, m.IsGhost, codeContext);
+ ResolveBlockStatement(m.Body, m);
+ SolveAllTypeConstraints();
}
// attributes are allowed to mention both in- and out-parameters (including the implicit _k, for colemmas)
- ResolveAttributes(m.Attributes, new ResolveOpts(m, false, true));
+ ResolveAttributes(m.Attributes, new ResolveOpts(m, false));
scope.PopMarker(); // for the out-parameters and outermost-level locals
scope.PopMarker(); // for the in-parameters
@@ -3708,7 +4648,7 @@ namespace Microsoft.Dafny
Contract.Requires(iter != null);
scope.PushMarker();
if (iter.SignatureIsOmitted) {
- Error(iter, "iterator signature can be omitted only in refining methods");
+ reporter.Error(MessageSource.Resolver, iter, "iterator signature can be omitted only in refining methods");
}
var option = iter.TypeArgs.Count == 0 ? new ResolveTypeOption(iter) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);
// resolve the types of the parameters
@@ -3730,7 +4670,7 @@ namespace Microsoft.Dafny
Contract.Requires(currentClass == null);
Contract.Ensures(currentClass == null);
- var initialErrorCount = ErrorCount;
+ var initialErrorCount = reporter.Count(ErrorLevel.Error);
// Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported
scope.PushMarker();
@@ -3744,26 +4684,22 @@ namespace Microsoft.Dafny
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];
- ResolveExpression(e, new ResolveOpts(iter, false, true));
+ ResolveExpression(e, new ResolveOpts(iter, false));
// any type is fine, but associate this type with the corresponding _decreases<n> field
var d = iter.DecreasesFields[i];
- if (!UnifyTypes(d.Type, e.Type)) {
- // bummer, there was a use--and a bad use--of the field before, so this won't be the best of error messages
- Error(e, "type of field {0} is {1}, but has been constrained elsewhere to be of type {2}", d.Name, e.Type, d.Type);
- }
+ // If the following type constraint does not hold, then: Bummer, there was a use--and a bad use--of the field before, so this won't be the best of error messages
+ ConstrainTypes(d.Type, e.Type, e, "type of field {0} is {1}, but has been constrained elsewhere to be of type {2}", d.Name, e.Type, d.Type);
}
foreach (FrameExpression fe in iter.Reads.Expressions) {
- ResolveFrameExpression(fe, true, false, iter);
+ ResolveFrameExpression(fe, true, iter);
}
foreach (FrameExpression fe in iter.Modifies.Expressions) {
- ResolveFrameExpression(fe, false, false, iter);
+ ResolveFrameExpression(fe, false, iter);
}
foreach (MaybeFreeExpression e in iter.Requires) {
- ResolveExpression(e.E, new ResolveOpts(iter, false, true));
+ ResolveExpression(e.E, new ResolveOpts(iter, false));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Precondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Precondition must be a boolean (got {0})", e.E.Type);
}
scope.PopMarker(); // for the in-parameters
@@ -3775,34 +4711,28 @@ namespace Microsoft.Dafny
Contract.Assert(scope.AllowInstance);
foreach (MaybeFreeExpression e in iter.YieldRequires) {
- ResolveExpression(e.E, new ResolveOpts(iter, false, true));
+ ResolveExpression(e.E, new ResolveOpts(iter, false));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Yield precondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Yield precondition must be a boolean (got {0})", e.E.Type);
}
foreach (MaybeFreeExpression e in iter.YieldEnsures) {
- ResolveExpression(e.E, new ResolveOpts(iter, true, true));
+ ResolveExpression(e.E, new ResolveOpts(iter, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Yield postcondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Yield postcondition must be a boolean (got {0})", e.E.Type);
}
foreach (MaybeFreeExpression e in iter.Ensures) {
- ResolveExpression(e.E, new ResolveOpts(iter, true, true));
+ ResolveExpression(e.E, new ResolveOpts(iter, true));
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(e.E, "Postcondition must be a boolean (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, e.E, "Postcondition must be a boolean (got {0})", e.E.Type);
}
- ResolveAttributes(iter.Attributes, new ResolveOpts(iter, false, true));
+ ResolveAttributes(iter.Attributes, new ResolveOpts(iter, false));
- var postSpecErrorCount = ErrorCount;
+ var postSpecErrorCount = reporter.Count(ErrorLevel.Error);
// Resolve body
if (iter.Body != null) {
- ResolveBlockStatement(iter.Body, false, iter);
+ ResolveBlockStatement(iter.Body, iter);
}
currentClass = null;
@@ -3840,10 +4770,10 @@ namespace Microsoft.Dafny
ens.Add(new MaybeFreeExpression(valid_call));
// ensures this._reads == old(ReadsClause);
var modSetSingletons = new List<Expression>();
- Expression frameSet = new SetDisplayExpr(iter.tok, modSetSingletons);
+ Expression frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons);
foreach (var fr in iter.Reads.Expressions) {
if (fr.FieldName != null) {
- Error(fr.tok, "sorry, a reads clause for an iterator is not allowed to designate specific fields");
+ reporter.Error(MessageSource.Resolver, fr.tok, "sorry, a reads clause for an iterator is not allowed to designate specific fields");
} else if (fr.E.Type.IsRefType) {
modSetSingletons.Add(fr.E);
} else {
@@ -3855,10 +4785,10 @@ namespace Microsoft.Dafny
new OldExpr(iter.tok, frameSet))));
// ensures this._modifies == old(ModifiesClause);
modSetSingletons = new List<Expression>();
- frameSet = new SetDisplayExpr(iter.tok, modSetSingletons);
+ frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons);
foreach (var fr in iter.Modifies.Expressions) {
if (fr.FieldName != null) {
- Error(fr.tok, "sorry, a modifies clause for an iterator is not allowed to designate specific fields");
+ reporter.Error(MessageSource.Resolver, fr.tok, "sorry, a modifies clause for an iterator is not allowed to designate specific fields");
} else if (fr.E.Type.IsRefType) {
modSetSingletons.Add(fr.E);
} else {
@@ -3871,7 +4801,7 @@ namespace Microsoft.Dafny
// ensures this._new == {};
ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,
new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), "_new"),
- new SetDisplayExpr(iter.tok, new List<Expression>()))));
+ new SetDisplayExpr(iter.tok, true, new List<Expression>()))));
// ensures this._decreases0 == old(DecreasesClause[0]) && ...;
Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count);
for (int i = 0; i < iter.Decreases.Expressions.Count; i++) {
@@ -4044,7 +4974,7 @@ namespace Microsoft.Dafny
// nothing to resolve
} else if (type is MapType) {
var mt = (MapType)type;
- var errorCount = ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
int typeArgumentCount = 0;
if (mt.HasTypeArg()) {
ResolveType(tok, mt.Domain, context, option, defaultTypeArguments);
@@ -4065,19 +4995,19 @@ namespace Microsoft.Dafny
}
// defaults and auto have been applied; check if we now have the right number of arguments
if (2 != typeArgumentCount) {
- Error(tok, "Wrong number of type arguments ({0} instead of 2) passed to type: {1}", typeArgumentCount, mt.CollectionTypeName);
+ reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments ({0} instead of 2) passed to type: {1}", typeArgumentCount, mt.CollectionTypeName);
// add proxy types, to make sure that MapType will have have a non-null Arg/Domain and Range
if (typeArgumentCount == 0) {
mt.SetTypeArg(new InferredTypeProxy());
}
mt.SetRangetype(new InferredTypeProxy());
}
- if (errorCount == ErrorCount && (mt.Domain.IsSubrangeType || mt.Range.IsSubrangeType)) {
- Error(tok, "sorry, cannot instantiate collection type with a subrange type");
+ if (errorCount == reporter.Count(ErrorLevel.Error) && (mt.Domain.IsSubrangeType || mt.Range.IsSubrangeType)) {
+ reporter.Error(MessageSource.Resolver, tok, "sorry, cannot instantiate collection type with a subrange type");
}
} else if (type is CollectionType) {
var t = (CollectionType)type;
- var errorCount = ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
if (t.HasTypeArg()) {
ResolveType(tok, t.Arg, context, option, defaultTypeArguments);
} else if (option.Opt != ResolveTypeOptionEnum.DontInfer) {
@@ -4090,13 +5020,13 @@ namespace Microsoft.Dafny
}
if (!t.HasTypeArg()) {
// defaults and auto have been applied; check if we now have the right number of arguments
- Error(tok, "Wrong number of type arguments (0 instead of 1) passed to type: {0}", t.CollectionTypeName);
+ reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments (0 instead of 1) passed to type: {0}", t.CollectionTypeName);
// add a proxy type, to make sure that CollectionType will have have a non-null Arg
t.SetTypeArg(new InferredTypeProxy());
}
- if (errorCount == ErrorCount && t.Arg.IsSubrangeType) {
- Error(tok, "sorry, cannot instantiate collection type with a subrange type");
+ if (errorCount == reporter.Count(ErrorLevel.Error) && t.Arg.IsSubrangeType) {
+ reporter.Error(MessageSource.Resolver, tok, "sorry, cannot instantiate collection type with a subrange type");
}
} else if (type is UserDefinedType) {
@@ -4105,34 +5035,47 @@ namespace Microsoft.Dafny
// Apparently, this type has already been resolved
return null;
}
- var prevErrorCount = ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
if (t.NamePath is ExprDotName) {
- var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true, true), allowDanglingDotName, option, defaultTypeArguments);
+ var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true), allowDanglingDotName, option, defaultTypeArguments);
if (ret != null) {
return ret;
}
} else {
var s = (NameSegment)t.NamePath;
- ResolveNameSegment_Type(s, new ResolveOpts(context, true, true), option, defaultTypeArguments);
+ ResolveNameSegment_Type(s, new ResolveOpts(context, true), option, defaultTypeArguments);
}
- if (ErrorCount == prevErrorCount) {
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
var r = t.NamePath.Resolved as Resolver_IdentifierExpr;
if (r == null || !(r.Type is Resolver_IdentifierExpr.ResolverType_Type)) {
- Error(t.tok, "expected type");
+ reporter.Error(MessageSource.Resolver, t.tok, "expected type");
} else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type && r.TypeParamDecl != null) {
t.ResolvedParam = r.TypeParamDecl;
} else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type) {
var d = r.Decl;
if (d is OpaqueTypeDecl) {
- t.ResolvedParam = ((OpaqueTypeDecl)d).TheType; // resolve like a type parameter, and it may have type parameters if it's an opaque type
+ var dd = (OpaqueTypeDecl)d;
+ if (dd.Module.ClonedFrom != null && dd.Module.ClonedFrom.ExclusiveRefinement != null) {
+ t.ResolvedParam = ((OpaqueTypeDecl)dd.ClonedFrom).TheType;
+ t.ResolvedClass = d; // Store the decl, so the compiler will generate the fully qualified name
+ } else {
+ t.ResolvedParam = ((OpaqueTypeDecl)d).TheType;
+ // resolve like a type parameter, and it may have type parameters if it's an opaque type
+ t.ResolvedClass = d; // Store the decl, so the compiler will generate the fully qualified name
+ }
} else if (d is NewtypeDecl) {
var dd = (NewtypeDecl)d;
+ if (DafnyOptions.O.IronDafny) {
+ while (dd.ClonedFrom != null) {
+ dd = (NewtypeDecl)dd.ClonedFrom;
+ }
+ }
var caller = context as ICallable;
if (caller != null) {
caller.EnclosingModule.CallGraph.AddEdge(caller, dd);
if (caller == dd) {
// detect self-loops here, since they don't show up in the graph's SSC methods
- Error(dd.tok, "recursive dependency involving a newtype: {0} -> {0}", dd.Name);
+ reporter.Error(MessageSource.Resolver, dd.tok, "recursive dependency involving a newtype: {0} -> {0}", dd.Name);
}
}
t.ResolvedClass = dd;
@@ -4147,7 +5090,7 @@ namespace Microsoft.Dafny
}
// defaults and auto have been applied; check if we now have the right number of arguments
if (d.TypeArgs.Count != t.TypeArgs.Count) {
- Error(t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", t.TypeArgs.Count, d.TypeArgs.Count, d.WhatKind, t.Name);
+ reporter.Error(MessageSource.Resolver, t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", t.TypeArgs.Count, d.TypeArgs.Count, d.WhatKind, t.Name);
}
}
@@ -4233,7 +5176,8 @@ namespace Microsoft.Dafny
} else if (a is ObjectType) {
return b is ObjectType;
} else if (a is SetType) {
- return b is SetType && UnifyTypes(((SetType)a).Arg, ((SetType)b).Arg);
+ return b is SetType && ((SetType)a).Finite == ((SetType)b).Finite &&
+ UnifyTypes(((SetType)a).Arg, ((SetType)b).Arg);
} else if (a is MultiSetType) {
return b is MultiSetType && UnifyTypes(((MultiSetType)a).Arg, ((MultiSetType)b).Arg);
} else if (a is MapType) {
@@ -4241,13 +5185,60 @@ namespace Microsoft.Dafny
UnifyTypes(((MapType)a).Domain, ((MapType)b).Domain) && UnifyTypes(((MapType)a).Range, ((MapType)b).Range);
} else if (a is SeqType) {
return b is SeqType && UnifyTypes(((SeqType)a).Arg, ((SeqType)b).Arg);
- } else if (a is UserDefinedType) {
- if (!(b is UserDefinedType)) {
- return false;
+ } else if (a is UserDefinedType || b is UserDefinedType) {
+ if (!(a is UserDefinedType) && b is UserDefinedType) {
+ var x = a;
+ a = b;
+ b = x;
}
+
var aa = (UserDefinedType)a;
+ var rca = aa.ResolvedClass;
+ // traits are currently unfriendly to irondafny features.
+ if (DafnyOptions.O.IronDafny && !(rca is TraitDecl)) {
+ if (rca != null) {
+ while (rca.ClonedFrom != null || rca.ExclusiveRefinement != null) {
+ if (rca.ClonedFrom != null) {
+ rca = (TopLevelDecl)rca.ClonedFrom;
+ } else {
+ Contract.Assert(rca.ExclusiveRefinement != null);
+ rca = rca.ExclusiveRefinement;
+ }
+ }
+ }
+ }
+
+ if (!(b is UserDefinedType)) {
+ return DafnyOptions.O.IronDafny && rca is TypeSynonymDecl && UnifyTypes(((TypeSynonymDecl)rca).Rhs, b);
+ }
+
var bb = (UserDefinedType)b;
- if (aa.ResolvedClass != null && aa.ResolvedClass == bb.ResolvedClass) {
+ var rcb = bb.ResolvedClass;
+ // traits are currently unfriendly to irondafny features.
+ if (DafnyOptions.O.IronDafny && !(rca is TraitDecl) && !(rcb is TraitDecl)) {
+ if (rcb != null) {
+ while (rcb.ClonedFrom != null || rcb.ExclusiveRefinement != null) {
+ if (rcb.ClonedFrom != null) {
+ rcb = (TopLevelDecl)rcb.ClonedFrom;
+ } else {
+ Contract.Assert(rcb.ExclusiveRefinement != null);
+ rcb = rcb.ExclusiveRefinement;
+ }
+ }
+ }
+ if (rca is TypeSynonymDecl || rcb is TypeSynonymDecl) {
+ var aaa = a;
+ var bbb = b;
+ if (rca is TypeSynonymDecl) {
+ aaa = ((TypeSynonymDecl)rca).Rhs;
+ }
+ if (rcb is TypeSynonymDecl) {
+ bbb = ((TypeSynonymDecl)rcb).Rhs;
+ }
+ return UnifyTypes(aaa, bbb);
+ }
+ }
+ if (rca != null && Object.ReferenceEquals(rca, rcb)) {
// these are both resolved class/datatype types
Contract.Assert(aa.TypeArgs.Count == bb.TypeArgs.Count);
bool successSoFar = true;
@@ -4255,13 +5246,12 @@ namespace Microsoft.Dafny
successSoFar = UnifyTypes(aa.TypeArgs[i], bb.TypeArgs[i]);
}
return successSoFar;
- }
- else if ((bb.ResolvedClass is TraitDecl) && (aa.ResolvedClass is TraitDecl)) {
- return ((TraitDecl)bb.ResolvedClass).FullCompileName == ((TraitDecl)aa.ResolvedClass).FullCompileName;
- } else if ((bb.ResolvedClass is ClassDecl) && (aa.ResolvedClass is TraitDecl)) {
- return ((ClassDecl)bb.ResolvedClass).TraitsObj.Any(tr => tr.FullCompileName == ((TraitDecl)aa.ResolvedClass).FullCompileName);
- } else if ((aa.ResolvedClass is ClassDecl) && (bb.ResolvedClass is TraitDecl)) {
- return ((ClassDecl)aa.ResolvedClass).TraitsObj.Any(tr => tr.FullCompileName == ((TraitDecl)bb.ResolvedClass).FullCompileName);
+ } else if (rcb is TraitDecl && rca is TraitDecl) {
+ return rca == rcb;
+ } else if (rcb is ClassDecl && rca is TraitDecl) {
+ return ((ClassDecl)rcb).TraitsObj.Contains(rca);
+ } else if (rca is ClassDecl && rcb is TraitDecl) {
+ return ((ClassDecl)rca).TraitsObj.Contains(rcb);
} else if (aa.ResolvedParam != null && aa.ResolvedParam == bb.ResolvedParam) {
// type parameters
if (aa.TypeArgs.Count != bb.TypeArgs.Count) {
@@ -4279,6 +5269,10 @@ namespace Microsoft.Dafny
// something is wrong; either aa or bb wasn't properly resolved, or they don't unify
return false;
}
+ } else if (a is Resolver_IdentifierExpr.ResolverType_Type) {
+ return b is Resolver_IdentifierExpr.ResolverType_Type;
+ } else if (a is Resolver_IdentifierExpr.ResolverType_Module) {
+ return b is Resolver_IdentifierExpr.ResolverType_Module;
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
}
@@ -4354,7 +5348,9 @@ namespace Microsoft.Dafny
// fine
} else if (opProxy.AllowChar && t is CharType) {
// fine
- } else if (opProxy.AllowSetVarieties && (t is SetType || t is MultiSetType)) {
+ } else if (opProxy.AllowSetVarieties && ((t is SetType && ((SetType)t).Finite) || t is MultiSetType)) {
+ // fine
+ } else if (opProxy.AllowISet && (t is SetType && !((SetType)t).Finite)) {
// fine
} else if (opProxy.AllowSeq && t is SeqType) {
// fine
@@ -4365,7 +5361,7 @@ namespace Microsoft.Dafny
} else if (proxy is IndexableTypeProxy) {
var iProxy = (IndexableTypeProxy)proxy;
if (t is SeqType) {
- if (!UnifyTypes(iProxy.Domain, new OperationTypeProxy(true, false, false, false, false))) {
+ if (!UnifyTypes(iProxy.Domain, new OperationTypeProxy(true, false, false, false, false, false))) {
return false;
} else if (!UnifyTypes(iProxy.Range, ((SeqType)t).Arg)) {
return false;
@@ -4374,7 +5370,7 @@ namespace Microsoft.Dafny
}
} else if (iProxy.AllowArray && t.IsArrayType && t.AsArrayType.Dims == 1) {
Type elType = UserDefinedType.ArrayElementType(t);
- if (!UnifyTypes(iProxy.Domain, new OperationTypeProxy(true, false, false, false, false))) {
+ if (!UnifyTypes(iProxy.Domain, new OperationTypeProxy(true, false, false, false, false, false))) {
return false;
} else if (!UnifyTypes(iProxy.Range, elType)) {
return false;
@@ -4400,7 +5396,7 @@ namespace Microsoft.Dafny
} else if (t is MultiSetType) {
if (!UnifyTypes(iProxy.Domain, ((MultiSetType)t).Arg)) {
return false;
- } else if (!UnifyTypes(iProxy.Range, new OperationTypeProxy(true, false, false, false, false))) {
+ } else if (!UnifyTypes(iProxy.Range, new OperationTypeProxy(true, false, false, false, false, false))) {
return false;
} else if (!UnifyTypes(iProxy.Arg, iProxy.Domain)) {
return false;
@@ -4481,15 +5477,18 @@ namespace Microsoft.Dafny
} else if (a is CollectionTypeProxy) {
if (b is CollectionTypeProxy) {
- a.T = b;
- return UnifyTypes(((CollectionTypeProxy)a).Arg, ((CollectionTypeProxy)b).Arg);
+ var argUnificationSuccess = UnifyTypes(((CollectionTypeProxy)a).Arg, ((CollectionTypeProxy)b).Arg);
+ if (argUnificationSuccess) {
+ a.T = b;
+ }
+ return argUnificationSuccess;
} else if (b is OperationTypeProxy) {
var proxy = (OperationTypeProxy)b;
- if (proxy.AllowSeq && proxy.AllowSetVarieties) {
+ if (proxy.AllowSeq && proxy.AllowSetVarieties && proxy.AllowISet) {
b.T = a; // a is a stronger constraint than b
} else {
// a says set<T>,seq<T> and b says numeric,set; the intersection is set<T>
- var c = new SetType(((CollectionTypeProxy)a).Arg);
+ var c = new SetType(true, ((CollectionTypeProxy)a).Arg);
return AssignProxyAfterCycleCheck(a, c) && AssignProxyAfterCycleCheck(b, c);
}
return true;
@@ -4497,7 +5496,7 @@ namespace Microsoft.Dafny
var pa = (CollectionTypeProxy)a;
var ib = (IndexableTypeProxy)b;
// pa is:
- // set(Arg) or multiset(Arg) or seq(Arg) or map(Arg, anyRange) or imap(Arg, anyRange)
+ // set(Arg) or iset(Arg) or multiset(Arg) or seq(Arg) or map(Arg, anyRange) or imap(Arg, anyRange)
// ib is:
// multiset(Arg) or
// seq(Arg) or
@@ -4525,15 +5524,16 @@ namespace Microsoft.Dafny
var h = pa.AllowChar && pb.AllowChar;
var q = pa.AllowSeq && pb.AllowSeq;
var s = pa.AllowSetVarieties && pb.AllowSetVarieties;
- if (!i && !r && !h && !q && !s) {
+ var t = pa.AllowISet && pb.AllowISet;
+ if (!i && !r && !h && !q && !s && !t) {
// over-constrained
return false;
- } else if (i == pa.AllowInts && r == pa.AllowReals && h == pa.AllowChar && q == pa.AllowSeq && s == pa.AllowSetVarieties) {
+ } else if (i == pa.AllowInts && r == pa.AllowReals && h == pa.AllowChar && q == pa.AllowSeq && s == pa.AllowSetVarieties && t == pa.AllowISet) {
b.T = a; // a has the stronger requirement
- } else if (i == pb.AllowInts && r == pb.AllowReals && h == pb.AllowChar && q == pb.AllowSeq && s == pb.AllowSetVarieties) {
+ } else if (i == pb.AllowInts && r == pb.AllowReals && h == pb.AllowChar && q == pb.AllowSeq && s == pb.AllowSetVarieties && t == pb.AllowISet) {
a.T = b; // b has the stronger requirement
} else {
- Type c = !i && !r && h && !q && !s ? new CharType() : (Type)new OperationTypeProxy(i, r, h, q, s);
+ Type c = !i && !r && h && !q && !s && !t? new CharType() : (Type)new OperationTypeProxy(i, r, h, q, s, t);
// the calls to AssignProxyAfterCycleCheck are needed only when c is a non-proxy type, but it doesn't
// hurt to do them in both cases
return AssignProxyAfterCycleCheck(a, c) && AssignProxyAfterCycleCheck(b, c);
@@ -4604,48 +5604,35 @@ namespace Microsoft.Dafny
return at;
}
- /// <summary>
- /// "specContextOnly" means that the statement must be erasable, that is, it should be okay to omit it
- /// at run time. That means it must not have any side effects on non-ghost variables, for example.
- /// </summary>
- public void ResolveStatement(Statement stmt, bool specContextOnly, ICodeContext codeContext) {
+ public void ResolveStatement(Statement stmt, ICodeContext codeContext) {
Contract.Requires(stmt != null);
Contract.Requires(codeContext != null);
if (!(stmt is ForallStmt)) { // forall statements do their own attribute resolution below
- ResolveAttributes(stmt.Attributes, new ResolveOpts(codeContext, true, true));
+ ResolveAttributes(stmt.Attributes, new ResolveOpts(codeContext, true));
}
if (stmt is PredicateStmt) {
PredicateStmt s = (PredicateStmt)stmt;
- s.IsGhost = true;
- ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(s.Expr, new ResolveOpts(codeContext, true));
Contract.Assert(s.Expr.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(s.Expr.Type, Type.Bool)) {
- Error(s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type);
- }
+ ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type);
} else if (stmt is PrintStmt) {
- PrintStmt s = (PrintStmt)stmt;
- ResolveAttributeArgs(s.Args, new ResolveOpts(codeContext, false, specContextOnly), false);
- if (specContextOnly) {
- Error(stmt, "print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
- }
+ var s = (PrintStmt)stmt;
+ var opts = new ResolveOpts(codeContext, false);
+ s.Args.Iter(e => ResolveExpression(e, opts));
} else if (stmt is BreakStmt) {
var s = (BreakStmt)stmt;
if (s.TargetLabel != null) {
Statement target = labeledStatements.Find(s.TargetLabel);
if (target == null) {
- Error(s, "break label is undefined or not in scope: {0}", s.TargetLabel);
+ reporter.Error(MessageSource.Resolver, s, "break label is undefined or not in scope: {0}", s.TargetLabel);
} else {
s.TargetStmt = target;
- bool targetIsLoop = target is WhileStmt || target is AlternativeLoopStmt;
- if (specContextOnly && !s.TargetStmt.IsGhost && !inSpecOnlyContext[s.TargetStmt]) {
- Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure"));
- }
}
} else {
if (loopStack.Count < s.BreakCount) {
- Error(s, "trying to break out of more loop levels than there are enclosing loops");
+ reporter.Error(MessageSource.Resolver, s, "trying to break out of more loop levels than there are enclosing loops");
} else {
Statement target = loopStack[loopStack.Count - s.BreakCount];
if (target.Labels == null) {
@@ -4653,20 +5640,15 @@ namespace Microsoft.Dafny
target.Labels = new LList<Label>(new Label(target.Tok, null), null);
}
s.TargetStmt = target;
- if (specContextOnly && !target.IsGhost && !inSpecOnlyContext[target]) {
- Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost loop");
- }
}
}
} else if (stmt is ProduceStmt) {
var kind = stmt is YieldStmt ? "yield" : "return";
if (stmt is YieldStmt && !(codeContext is IteratorDecl)) {
- Error(stmt, "yield statement is allowed only in iterators");
+ reporter.Error(MessageSource.Resolver, stmt, "yield statement is allowed only in iterators");
} else if (stmt is ReturnStmt && !(codeContext is Method)) {
- Error(stmt, "return statement is allowed only in method");
- } else if (specContextOnly && !codeContext.IsGhost) {
- Error(stmt, "{0} statement is not allowed in this context (because it is guarded by a specification-only expression)", kind);
+ reporter.Error(MessageSource.Resolver, stmt, "return statement is allowed only in method");
}
var s = (ProduceStmt)stmt;
if (s.rhss != null) {
@@ -4674,7 +5656,7 @@ namespace Microsoft.Dafny
if (cmc == null) {
// an error has already been reported above
} else if (cmc.Outs.Count != s.rhss.Count) {
- Error(s, "number of {2} parameters does not match declaration (found {0}, expected {1})", s.rhss.Count, cmc.Outs.Count, kind);
+ reporter.Error(MessageSource.Resolver, s, "number of {2} parameters does not match declaration (found {0}, expected {1})", s.rhss.Count, cmc.Outs.Count, kind);
} else {
Contract.Assert(s.rhss.Count > 0);
// Create a hidden update statement using the out-parameter formals, resolve the RHS, and check that the RHS is good.
@@ -4697,13 +5679,13 @@ namespace Microsoft.Dafny
}
s.hiddenUpdate = new UpdateStmt(s.Tok, s.EndTok, formals, s.rhss, true);
// resolving the update statement will check for return/yield statement specifics.
- ResolveStatement(s.hiddenUpdate, specContextOnly, codeContext);
+ ResolveStatement(s.hiddenUpdate, codeContext);
}
} else {// this is a regular return/yield statement.
s.hiddenUpdate = null;
}
} else if (stmt is ConcreteUpdateStatement) {
- ResolveConcreteUpdateStmt((ConcreteUpdateStatement)stmt, specContextOnly, codeContext);
+ ResolveConcreteUpdateStmt((ConcreteUpdateStatement)stmt, codeContext);
} else if (stmt is VarDeclStmt) {
var s = (VarDeclStmt)stmt;
// We have three cases.
@@ -4725,10 +5707,6 @@ namespace Microsoft.Dafny
foreach (var local in s.Locals) {
ResolveType(local.Tok, local.OptionalType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
local.type = local.OptionalType;
- if (specContextOnly) {
- // a local variable in a specification-only context might as well be ghost
- local.IsGhost = true;
- }
}
// Resolve the UpdateStmt, if any
if (s.Update is UpdateStmt) {
@@ -4743,64 +5721,76 @@ namespace Microsoft.Dafny
lhs.Type = local.Type;
}
// resolve the whole thing
- ResolveConcreteUpdateStmt(s.Update, specContextOnly, codeContext);
+ ResolveConcreteUpdateStmt(s.Update, codeContext);
}
// Add the locals to the scope
foreach (var local in s.Locals) {
- if (!scope.Push(local.Name, local)) {
- Error(local.Tok, "Duplicate local-variable name: {0}", local.Name);
- }
+ ScopePushAndReport(scope, local, "local-variable");
}
// With the new locals in scope, it's now time to resolve the attributes on all the locals
foreach (var local in s.Locals) {
- ResolveAttributes(local.Attributes, new ResolveOpts(codeContext, true, true));
+ ResolveAttributes(local.Attributes, new ResolveOpts(codeContext, true));
}
// Resolve the AssignSuchThatStmt, if any
if (s.Update is AssignSuchThatStmt) {
- ResolveConcreteUpdateStmt(s.Update, specContextOnly, codeContext);
+ ResolveConcreteUpdateStmt(s.Update, codeContext);
}
// Update the VarDeclStmt's ghost status according to its components
- if (!s.IsGhost) {
- s.IsGhost = (s.Update == null || s.Update.IsGhost) && s.Locals.All(v => v.IsGhost);
- }
foreach (var local in s.Locals)
{
if (Attributes.Contains(local.Attributes, "assumption"))
{
if (currentMethod == null)
{
- Error(local.Tok, "assumption variable can only be declared in a method");
- }
- if (!local.IsGhost)
- {
- Error(local.Tok, "assumption variable must be ghost");
+ reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable can only be declared in a method");
}
if (!(local.Type.IsBoolType))
{
- Error(s, "assumption variable must be of type 'bool'");
+ reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable must be of type 'bool'");
+ }
+ if (!local.IsGhost) {
+ reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable must be ghost");
}
}
}
-
+ } else if (stmt is LetStmt) {
+ LetStmt s = (LetStmt)stmt;
+ foreach (var rhs in s.RHSs) {
+ ResolveExpression(rhs, new ResolveOpts(codeContext, true));
+ }
+ if (s.LHSs.Count != s.RHSs.Count) {
+ reporter.Error(MessageSource.Resolver, stmt, "let statement must have same number of LHSs (found {0}) as RHSs (found {1})", s.LHSs.Count, s.RHSs.Count);
+ }
+ var i = 0;
+ foreach (var lhs in s.LHSs) {
+ var rhsType = i < s.RHSs.Count ? s.RHSs[i].Type : new InferredTypeProxy();
+ ResolveCasePattern(lhs, rhsType, codeContext);
+ // Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors
+ var c = 0;
+ foreach (var bv in lhs.Vars) {
+ ScopePushAndReport(scope, bv, "local_variable");
+ c++;
+ }
+ if (c == 0) {
+ // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal
+ reporter.Error(MessageSource.Resolver, lhs.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable");
+ }
+ i++;
+ }
} else if (stmt is AssignStmt) {
AssignStmt s = (AssignStmt)stmt;
- int prevErrorCount = ErrorCount;
- ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true, specContextOnly)); // allow ghosts for now, tighted up below
- bool lhsResolvedSuccessfully = ErrorCount == prevErrorCount;
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
+ ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true)); // allow ghosts for now, tighted up below
+ bool lhsResolvedSuccessfully = reporter.Count(ErrorLevel.Error) == prevErrorCount;
Contract.Assert(s.Lhs.Type != null); // follows from postcondition of ResolveExpression
// check that LHS denotes a mutable variable or a field
- bool lvalueIsGhost = false;
var lhs = s.Lhs.Resolved;
if (lhs is IdentifierExpr) {
IVariable var = ((IdentifierExpr)lhs).Var;
if (var == null) {
// the LHS didn't resolve correctly; some error would already have been reported
} else {
- lvalueIsGhost = var.IsGhost || codeContext.IsGhost;
CheckIsLvalue(lhs, codeContext);
- if (!lvalueIsGhost && specContextOnly) {
- Error(stmt, "Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
- }
var localVar = var as LocalVariable;
if (localVar != null && currentMethod != null && Attributes.Contains(localVar.Attributes, "assumption"))
@@ -4818,25 +5808,13 @@ namespace Microsoft.Dafny
}
else
{
- Error(stmt, string.Format("there may be at most one assignment to an assumption variable, the RHS of which must match the expression \"{0} && <boolean expression>\"", localVar.Name));
+ reporter.Error(MessageSource.Resolver, stmt, string.Format("there may be at most one assignment to an assumption variable, the RHS of which must match the expression \"{0} && <boolean expression>\"", localVar.Name));
}
}
}
} else if (lhs is MemberSelectExpr) {
var fse = (MemberSelectExpr)lhs;
if (fse.Member != null) { // otherwise, an error was reported above
- lvalueIsGhost = fse.Member.IsGhost;
- if (!lvalueIsGhost) {
- if (specContextOnly) {
- Error(stmt, "Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
- } else {
- // It is now that we wish we would have resolved s.Lhs to not allow ghosts. Too late, so we do
- // the next best thing.
- if (lhsResolvedSuccessfully && UsesSpecFeatures(fse.Obj)) {
- Error(stmt, "Assignment to non-ghost field is not allowed to use specification-only expressions in the receiver");
- }
- }
- }
CheckIsLvalue(fse, codeContext);
}
} else if (lhs is SeqSelectExpr) {
@@ -4844,52 +5822,26 @@ namespace Microsoft.Dafny
// LHS is fine, provided the "sequence" is really an array
if (lhsResolvedSuccessfully) {
Contract.Assert(slhs.Seq.Type != null);
- if (specContextOnly) {
- Error(stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
- }
CheckIsLvalue(slhs, codeContext);
}
} else if (lhs is MultiSelectExpr) {
- if (specContextOnly) {
- Error(stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)");
- }
CheckIsLvalue(lhs, codeContext);
} else {
CheckIsLvalue(lhs, codeContext);
}
- s.IsGhost = lvalueIsGhost;
Type lhsType = s.Lhs.Type;
if (s.Rhs is ExprRhs) {
ExprRhs rr = (ExprRhs)s.Rhs;
- ResolveExpression(rr.Expr, new ResolveOpts(codeContext, true, specContextOnly));
- if (!lvalueIsGhost) {
- CheckIsNonGhost(rr.Expr);
- }
+ ResolveExpression(rr.Expr, new ResolveOpts(codeContext, true));
Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(lhsType, rr.Expr.Type)) {
- Error(stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType);
- }
+ ConstrainTypes(lhsType, rr.Expr.Type, stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType);
} else if (s.Rhs is TypeRhs) {
TypeRhs rr = (TypeRhs)s.Rhs;
- Type t = ResolveTypeRhs(rr, stmt, lvalueIsGhost, codeContext);
- if (!lvalueIsGhost) {
- if (rr.ArrayDimensions != null) {
- foreach (var dim in rr.ArrayDimensions) {
- CheckIsNonGhost(dim);
- }
- }
- if (rr.InitCall != null) {
- foreach (var arg in rr.InitCall.Args) {
- CheckIsNonGhost(arg);
- }
- }
- }
- if (!UnifyTypes(lhsType, t)) {
- Error(stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType);
- }
+ Type t = ResolveTypeRhs(rr, stmt, codeContext);
+ ConstrainTypes(lhsType, t, stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType);
} else if (s.Rhs is HavocRhs) {
// nothing else to do
} else {
@@ -4898,181 +5850,86 @@ namespace Microsoft.Dafny
} else if (stmt is CallStmt) {
CallStmt s = (CallStmt)stmt;
- ResolveCallStmt(s, specContextOnly, codeContext, null);
+ ResolveCallStmt(s, codeContext, null);
} else if (stmt is BlockStmt) {
var s = (BlockStmt)stmt;
scope.PushMarker();
- ResolveBlockStatement(s, specContextOnly, codeContext);
- if (!s.IsGhost) {
- s.IsGhost = s.Body.All(ss => ss.IsGhost); // mark the block statement as ghost if all its substatements are ghost
- }
+ ResolveBlockStatement(s, codeContext);
scope.PopMarker();
} else if (stmt is IfStmt) {
IfStmt s = (IfStmt)stmt;
- bool branchesAreSpecOnly = specContextOnly;
if (s.Guard != null) {
- int prevErrorCount = ErrorCount;
- ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly));
+ ResolveExpression(s.Guard, new ResolveOpts(codeContext, true));
Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression
- bool successfullyResolved = ErrorCount == prevErrorCount;
- if (!UnifyTypes(s.Guard.Type, Type.Bool)) {
- Error(s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type);
- }
- if (!specContextOnly && successfullyResolved) {
- branchesAreSpecOnly = UsesSpecFeatures(s.Guard);
+ ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type);
+ }
+
+ scope.PushMarker();
+ if (s.IsExistentialGuard) {
+ var exists = (ExistsExpr)s.Guard;
+ foreach (var v in exists.BoundVars) {
+ ScopePushAndReport(scope, v, "bound-variable");
}
}
- s.IsGhost = branchesAreSpecOnly;
- ResolveStatement(s.Thn, branchesAreSpecOnly, codeContext);
+ ResolveBlockStatement(s.Thn, codeContext);
+ scope.PopMarker();
+
if (s.Els != null) {
- ResolveStatement(s.Els, branchesAreSpecOnly, codeContext);
- }
- if (!s.IsGhost && s.Thn.IsGhost && (s.Els == null || s.Els.IsGhost)) {
- // mark the entire 'if' statement as ghost if its branches are ghost
- s.IsGhost = true;
+ ResolveStatement(s.Els, codeContext);
}
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
- s.IsGhost = ResolveAlternatives(s.Alternatives, specContextOnly, null, codeContext);
- if (!s.IsGhost) {
- s.IsGhost = s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost));
- }
+ ResolveAlternatives(s.Alternatives, null, codeContext);
} else if (stmt is WhileStmt) {
WhileStmt s = (WhileStmt)stmt;
- bool bodyMustBeSpecOnly = specContextOnly;
var fvs = new HashSet<IVariable>();
- bool usesHeap = false, usesOldHeap = false;
- Type usesThis = null;
if (s.Guard != null) {
- int prevErrorCount = ErrorCount;
- ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly));
+ ResolveExpression(s.Guard, new ResolveOpts(codeContext, true));
Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression
- bool successfullyResolved = ErrorCount == prevErrorCount;
- Translator.ComputeFreeVariables(s.Guard, fvs, ref usesHeap, ref usesOldHeap, ref usesThis, false);
- if (!UnifyTypes(s.Guard.Type, Type.Bool)) {
- Error(s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type);
- }
- if (!specContextOnly && successfullyResolved) {
- bodyMustBeSpecOnly = UsesSpecFeatures(s.Guard);
- }
- }
-
- foreach (MaybeFreeExpression inv in s.Invariants) {
- ResolveAttributes(inv.Attributes, new ResolveOpts(codeContext, true, true));
- ResolveExpression(inv.E, new ResolveOpts(codeContext, true, true));
- Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression
- Translator.ComputeFreeVariables(inv.E, fvs, ref usesHeap, ref usesOldHeap, ref usesThis, false);
- if (!UnifyTypes(inv.E.Type, Type.Bool)) {
- Error(inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type);
- }
+ Translator.ComputeFreeVariables(s.Guard, fvs);
+ ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type);
}
- ResolveAttributes(s.Decreases.Attributes, new ResolveOpts(codeContext, true, true));
- foreach (Expression e in s.Decreases.Expressions) {
- ResolveExpression(e, new ResolveOpts(codeContext, true, true));
- if (e is WildcardExpr) {
- if (bodyMustBeSpecOnly) {
- Error(e, "'decreases *' is not allowed on ghost loops");
- } else if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) {
- Error(e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating");
- }
- }
- // any type is fine
- }
+ ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, fvs);
- if (s.Mod.Expressions != null) {
- ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true, true));
- foreach (FrameExpression fe in s.Mod.Expressions) {
- ResolveFrameExpression(fe, false, bodyMustBeSpecOnly, codeContext);
- Translator.ComputeFreeVariables(fe.E, fvs, ref usesHeap, ref usesOldHeap, ref usesThis, false);
- }
- }
- s.IsGhost = s.Body == null || bodyMustBeSpecOnly;
if (s.Body != null) {
loopStack.Add(s); // push
- if (s.Labels == null) { // otherwise, "s" is already in "inSpecOnlyContext" map
- inSpecOnlyContext.Add(s, specContextOnly);
- }
-
- ResolveStatement(s.Body, bodyMustBeSpecOnly, codeContext);
+ ResolveStatement(s.Body, codeContext);
loopStack.RemoveAt(loopStack.Count - 1); // pop
} else {
- string text = "havoc {";
- if (fvs.Count != 0) {
- string sep = "";
- foreach (var fv in fvs) {
- text += sep + fv.Name;
- sep = ", ";
- }
- }
- text += "};"; // always terminate with a semi-colon
- ReportAdditionalInformation(s.Tok, text, s.Tok.val.Length);
+ string text = "havoc {" + Util.Comma(", ", fvs, fv => fv.Name) + "};"; // always terminate with a semi-colon
+ reporter.Info(MessageSource.Resolver, s.Tok, text);
}
} else if (stmt is AlternativeLoopStmt) {
var s = (AlternativeLoopStmt)stmt;
- s.IsGhost = ResolveAlternatives(s.Alternatives, specContextOnly, s, codeContext);
- foreach (MaybeFreeExpression inv in s.Invariants) {
- ResolveExpression(inv.E, new ResolveOpts(codeContext, true, true));
- Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(inv.E.Type, Type.Bool)) {
- Error(inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type);
- }
- }
-
- foreach (Expression e in s.Decreases.Expressions) {
- ResolveExpression(e, new ResolveOpts(codeContext, true, true));
- if (e is WildcardExpr) {
- if (s.IsGhost) {
- Error(e, "'decreases *' is not allowed on ghost loops");
- } else if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) {
- Error(e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating");
- }
- }
- // any type is fine
- }
+ ResolveAlternatives(s.Alternatives, s, codeContext);
+ ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, null);
} else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
- int prevErrorCount = ErrorCount;
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
scope.PushMarker();
foreach (BoundVar v in s.BoundVars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate bound-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "local-variable");
ResolveType(v.tok, v.Type, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
}
- ResolveExpression(s.Range, new ResolveOpts(codeContext, true, specContextOnly));
+ ResolveExpression(s.Range, new ResolveOpts(codeContext, true));
Contract.Assert(s.Range.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(s.Range.Type, Type.Bool)) {
- Error(stmt, "range restriction in forall statement must be of type bool (instead got {0})", s.Range.Type);
- }
+ ConstrainTypes(s.Range.Type, Type.Bool, stmt, "range restriction in forall statement must be of type bool (instead got {0})", s.Range.Type);
foreach (var ens in s.Ens) {
- ResolveExpression(ens.E, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(ens.E, new ResolveOpts(codeContext, true));
Contract.Assert(ens.E.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(ens.E.Type, Type.Bool)) {
- Error(ens.E, "ensures condition is expected to be of type {0}, but is {1}", Type.Bool, ens.E.Type);
- }
+ ConstrainTypes(ens.E.Type, Type.Bool, ens.E, "ensures condition is expected to be of type {0}, but is {1}", Type.Bool, ens.E.Type);
}
// Since the range and postconditions are more likely to infer the types of the bound variables, resolve them
// first (above) and only then resolve the attributes (below).
- ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true, true));
-
- bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == ErrorCount && UsesSpecFeatures(s.Range));
- if (!bodyMustBeSpecOnly && prevErrorCount == ErrorCount) {
- var missingBounds = new List<BoundVar>();
- CheckTypeInference(s.Range); // we need to resolve operators before the call to DiscoverBounds
- s.Bounds = DiscoverBounds(s.Tok, s.BoundVars, s.Range, true, false, missingBounds);
- if (missingBounds.Count != 0) {
- bodyMustBeSpecOnly = true;
- }
- }
- s.IsGhost = s.Body == null || bodyMustBeSpecOnly;
+ ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true));
if (s.Body != null) {
// clear the labels for the duration of checking the body, because break statements are not allowed to leave a forall statement
@@ -5080,13 +5937,13 @@ namespace Microsoft.Dafny
var prevLoopStack = loopStack;
labeledStatements = new Scope<Statement>();
loopStack = new List<Statement>();
- ResolveStatement(s.Body, bodyMustBeSpecOnly, codeContext);
+ ResolveStatement(s.Body, codeContext);
labeledStatements = prevLblStmts;
loopStack = prevLoopStack;
}
scope.PopMarker();
- if (prevErrorCount == ErrorCount) {
+ if (prevErrorCount == reporter.Count(ErrorLevel.Error)) {
// determine the Kind and run some additional checks on the body
if (s.Ens.Count != 0) {
// The only supported kind with ensures clauses is Proof.
@@ -5110,13 +5967,13 @@ namespace Microsoft.Dafny
// add the conclusion of the calc as a free postcondition
var result = ((CalcStmt)s0).Result;
s.Ens.Add(new MaybeFreeExpression(result, true));
- ReportAdditionalInformation(s.Tok, "ensures " + Printer.ExprToString(result) + ";", s.Tok.val.Length);
+ reporter.Info(MessageSource.Resolver, s.Tok, "ensures " + Printer.ExprToString(result));
} else {
s.Kind = ForallStmt.ParBodyKind.Proof;
if (s.Body is BlockStmt && ((BlockStmt)s.Body).Body.Count == 0) {
// an empty statement, so don't produce any warning
} else {
- Warning(s.Tok, "the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause");
+ reporter.Warning(MessageSource.Resolver, s.Tok, "the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause");
}
}
}
@@ -5127,34 +5984,30 @@ namespace Microsoft.Dafny
} else if (stmt is ModifyStmt) {
var s = (ModifyStmt)stmt;
- ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true, true));
+ ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true));
foreach (FrameExpression fe in s.Mod.Expressions) {
- // (yes, say "modifies", not "modify", in the next line -- it seems to give a more readable error message
- ResolveFrameExpression(fe, false, specContextOnly, codeContext);
+ ResolveFrameExpression(fe, false, codeContext);
}
if (s.Body != null) {
- ResolveBlockStatement(s.Body, specContextOnly, codeContext);
+ ResolveBlockStatement(s.Body, codeContext);
}
- s.IsGhost = specContextOnly;
} else if (stmt is CalcStmt) {
- var prevErrorCount = ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
CalcStmt s = (CalcStmt)stmt;
- s.IsGhost = true;
if (s.Lines.Count > 0) {
var e0 = s.Lines.First();
- ResolveExpression(e0, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(e0, new ResolveOpts(codeContext, true));
Contract.Assert(e0.Type != null); // follows from postcondition of ResolveExpression
for (int i = 1; i < s.Lines.Count; i++) {
- if (i < s.Lines.Count - 1 || prevErrorCount == ErrorCount) { // do not resolve the dummy step if there were errors, it might generate more errors
+ if (i < s.Lines.Count - 1 || prevErrorCount == reporter.Count(ErrorLevel.Error)) { // do not resolve the dummy step if there were errors, it might generate more errors
var e1 = s.Lines[i];
- ResolveExpression(e1, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(e1, new ResolveOpts(codeContext, true));
Contract.Assert(e1.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e0.Type, e1.Type)) {
- Error(e1, "all lines in a calculation must have the same type (got {0} after {1})", e1.Type, e0.Type);
+ if (!ConstrainTypes(e0.Type, e1.Type, e1, "all lines in a calculation must have the same type (got {0} after {1})", e1.Type, e0.Type)) {
} else {
var step = s.StepOps[i - 1].StepExpr(e0, e1); // Use custom line operator
- ResolveExpression(step, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(step, new ResolveOpts(codeContext, true));
s.Steps.Add(step);
}
e0 = e1;
@@ -5167,124 +6020,523 @@ namespace Microsoft.Dafny
labeledStatements = new Scope<Statement>();
loopStack = new List<Statement>();
foreach (var h in s.Hints) {
- ResolveStatement(h, true, codeContext);
- CheckHintRestrictions(h);
+ ResolveStatement(h, codeContext);
}
labeledStatements = prevLblStmts;
loopStack = prevLoopStack;
}
- if (prevErrorCount == ErrorCount && s.Lines.Count > 0) {
+ if (prevErrorCount == reporter.Count(ErrorLevel.Error) && s.Lines.Count > 0) {
// do not build Result from the lines if there were errors, as it might be ill-typed and produce unnecessary resolution errors
s.Result = s.ResultOp.StepExpr(s.Lines.First(), s.Lines.Last());
} else {
s.Result = CalcStmt.DefaultOp.StepExpr(Expression.CreateIntLiteral(s.Tok, 0), Expression.CreateIntLiteral(s.Tok, 0));
}
- ResolveExpression(s.Result, new ResolveOpts(codeContext, true, true));
+ ResolveExpression(s.Result, new ResolveOpts(codeContext, true));
Contract.Assert(s.Result != null);
- Contract.Assert(prevErrorCount != ErrorCount || s.Steps.Count == s.Hints.Count);
+ Contract.Assert(prevErrorCount != reporter.Count(ErrorLevel.Error) || s.Steps.Count == s.Hints.Count);
} else if (stmt is MatchStmt) {
- MatchStmt s = (MatchStmt)stmt;
- bool bodyIsSpecOnly = specContextOnly;
- int prevErrorCount = ErrorCount;
- ResolveExpression(s.Source, new ResolveOpts(codeContext, true, specContextOnly));
- Contract.Assert(s.Source.Type != null); // follows from postcondition of ResolveExpression
- bool successfullyResolved = ErrorCount == prevErrorCount;
- if (!specContextOnly && successfullyResolved) {
- bodyIsSpecOnly = UsesSpecFeatures(s.Source);
- }
- UserDefinedType sourceType = null;
- DatatypeDecl dtd = null;
- if (s.Source.Type.IsDatatype) {
- sourceType = (UserDefinedType)s.Source.Type.NormalizeExpand();
- dtd = cce.NonNull((DatatypeDecl)sourceType.ResolvedClass);
+ ResolveMatchStmt(stmt, codeContext);
+ } else if (stmt is SkeletonStatement) {
+ var s = (SkeletonStatement)stmt;
+ reporter.Error(MessageSource.Resolver, s.Tok, "skeleton statements are allowed only in refining methods");
+ // nevertheless, resolve the underlying statement; hey, why not
+ if (s.S != null) {
+ ResolveStatement(s.S, codeContext);
}
- var subst = new Dictionary<TypeParameter, Type>();
- Dictionary<string, DatatypeCtor> ctors;
- if (dtd == null) {
- Error(s.Source, "the type of the match source expression must be a datatype (instead found {0})", s.Source.Type);
- ctors = null;
- } else {
- Contract.Assert(sourceType != null); // dtd and sourceType are set together above
- ctors = datatypeCtors[dtd];
- Contract.Assert(ctors != null); // dtd should have been inserted into datatypeCtors during a previous resolution stage
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException();
+ }
+ }
+
+ private void ResolveLoopSpecificationComponents(List<MaybeFreeExpression> invariants, Specification<Expression> decreases, Specification<FrameExpression> modifies, ICodeContext codeContext, HashSet<IVariable> fvs) {
+ Contract.Requires(invariants != null);
+ Contract.Requires(decreases != null);
+ Contract.Requires(modifies != null);
+ Contract.Requires(codeContext != null);
- // build the type-parameter substitution map for this use of the datatype
- for (int i = 0; i < dtd.TypeArgs.Count; i++) {
- subst.Add(dtd.TypeArgs[i], sourceType.TypeArgs[i]);
+ foreach (MaybeFreeExpression inv in invariants) {
+ ResolveAttributes(inv.Attributes, 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) {
+ Translator.ComputeFreeVariables(inv.E, fvs);
+ }
+ ConstrainTypes(inv.E.Type, Type.Bool, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type);
+ }
+
+ ResolveAttributes(decreases.Attributes, new ResolveOpts(codeContext, true));
+ foreach (Expression e in decreases.Expressions) {
+ ResolveExpression(e, new ResolveOpts(codeContext, true));
+ if (e is WildcardExpr) {
+ if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) {
+ reporter.Error(MessageSource.Resolver, e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating");
}
}
- s.IsGhost = bodyIsSpecOnly;
+ // any type is fine
+ }
+
+ ResolveAttributes(modifies.Attributes, new ResolveOpts(codeContext, true));
+ if (modifies.Expressions != null) {
+ foreach (FrameExpression fe in modifies.Expressions) {
+ ResolveFrameExpression(fe, false, codeContext);
+ if (fvs != null) {
+ Translator.ComputeFreeVariables(fe.E, fvs);
+ }
+ }
+ }
+ }
+
+ void ResolveMatchStmt(Statement stmt, ICodeContext codeContext) {
+ MatchStmt s = (MatchStmt)stmt;
+ DesugarMatchStmtWithTupleExpression(s);
- ISet<string> memberNamesUsed = new HashSet<string>();
- foreach (MatchCaseStmt mc in s.Cases) {
- DatatypeCtor ctor = null;
- if (ctors != null) {
- Contract.Assert(dtd != null);
- if (!ctors.TryGetValue(mc.Id, out ctor)) {
- Error(mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name);
+ ResolveExpression(s.Source, new ResolveOpts(codeContext, true));
+ Contract.Assert(s.Source.Type != null); // follows from postcondition of ResolveExpression
+ UserDefinedType sourceType = null;
+ DatatypeDecl dtd = null;
+ if (s.Source.Type.IsDatatype) {
+ sourceType = (UserDefinedType)s.Source.Type.NormalizeExpand();
+ dtd = cce.NonNull((DatatypeDecl)sourceType.ResolvedClass);
+ }
+ var subst = new Dictionary<TypeParameter, Type>();
+ Dictionary<string, DatatypeCtor> ctors;
+ if (dtd == null) {
+ reporter.Error(MessageSource.Resolver, s.Source, "the type of the match source expression must be a datatype (instead found {0})", s.Source.Type);
+ ctors = null;
+ } else {
+ Contract.Assert(sourceType != null); // dtd and sourceType are set together above
+ ctors = datatypeCtors[dtd];
+ Contract.Assert(ctors != null); // dtd should have been inserted into datatypeCtors during a previous resolution stage
+
+ // build the type-parameter substitution map for this use of the datatype
+ for (int i = 0; i < dtd.TypeArgs.Count; i++) {
+ subst.Add(dtd.TypeArgs[i], sourceType.TypeArgs[i]);
+ }
+ }
+
+ // convert CasePattern in MatchCaseExpr to BoundVar and flatten the MatchCaseExpr.
+ List<Tuple<CasePattern, BoundVar>> patternSubst = new List<Tuple<CasePattern, BoundVar>>();
+ if (dtd != null) {
+ DesugarMatchCaseStmt(s, dtd, patternSubst, codeContext);
+ }
+
+ ISet<string> memberNamesUsed = new HashSet<string>();
+ foreach (MatchCaseStmt mc in s.Cases) {
+ DatatypeCtor ctor = null;
+ if (ctors != null) {
+ Contract.Assert(dtd != null);
+ if (!ctors.TryGetValue(mc.Id, out ctor)) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name);
+ } else {
+ Contract.Assert(ctor != null); // follows from postcondition of TryGetValue
+ mc.Ctor = ctor;
+ if (ctor.Formals.Count != mc.Arguments.Count) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count);
+ }
+ if (memberNamesUsed.Contains(mc.Id)) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} appears in more than one case", mc.Id);
} else {
- Contract.Assert(ctor != null); // follows from postcondition of TryGetValue
- mc.Ctor = ctor;
- if (ctor.Formals.Count != mc.Arguments.Count) {
- Error(mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count);
- }
- if (memberNamesUsed.Contains(mc.Id)) {
- Error(mc.tok, "member {0} appears in more than one case", mc.Id);
- } else {
- memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used
- }
+ memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used
}
}
- scope.PushMarker();
- int i = 0;
+ }
+ scope.PushMarker();
+ int i = 0;
+ if (mc.Arguments != null) {
foreach (BoundVar v in mc.Arguments) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate parameter name: {0}", v.Name);
- }
+ scope.Push(v.Name, v);
ResolveType(v.tok, v.Type, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
if (ctor != null && i < ctor.Formals.Count) {
Formal formal = ctor.Formals[i];
Type st = SubstType(formal.Type, subst);
- if (!UnifyTypes(v.Type, st)) {
- Error(stmt, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st);
- }
+ ConstrainTypes(v.Type, st, stmt, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st);
v.IsGhost = formal.IsGhost;
+
+ // update the type of the boundvars in the MatchCaseToken
+ if (v.tok is MatchCaseToken) {
+ MatchCaseToken mt = (MatchCaseToken)v.tok;
+ foreach (Tuple<IToken, BoundVar, bool> entry in mt.varList) {
+ UnifyTypes(entry.Item2.Type, v.Type); // TODO: What if this unification fails? Can it? --KRML
+ }
+ }
}
i++;
}
+ }
+ foreach (Statement ss in mc.Body) {
+ ResolveStatement(ss, codeContext);
+ }
+ // substitute body to replace the case pat with v. This needs to happen
+ // after the body is resolved so we can scope the bv correctly.
+ if (patternSubst.Count > 0) {
+ MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(patternSubst);
+ List<Statement> list = new List<Statement>();
foreach (Statement ss in mc.Body) {
- ResolveStatement(ss, bodyIsSpecOnly, codeContext);
+ Statement clone = cloner.CloneStmt(ss);
+ // resolve it again since we just cloned it.
+ ResolveStatement(clone, codeContext);
+ list.Add(clone);
}
- scope.PopMarker();
+ mc.UpdateBody(list);
}
- if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
- // We could complain about the syntactic omission of constructors:
- // Error(stmt, "match statement does not cover all constructors");
- // but instead we let the verifier do a semantic check.
- // So, for now, record the missing constructors:
- foreach (var ctr in dtd.Ctors) {
- if (!memberNamesUsed.Contains(ctr.Name)) {
- s.MissingCases.Add(ctr);
+
+ scope.PopMarker();
+ }
+ if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
+ // We could complain about the syntactic omission of constructors:
+ // reporter.Error(MessageSource.Resolver, stmt, "match statement does not cover all constructors");
+ // but instead we let the verifier do a semantic check.
+ // So, for now, record the missing constructors:
+ foreach (var ctr in dtd.Ctors) {
+ if (!memberNamesUsed.Contains(ctr.Name)) {
+ s.MissingCases.Add(ctr);
+ }
+ }
+ Contract.Assert(memberNamesUsed.Count + s.MissingCases.Count == dtd.Ctors.Count);
+ }
+ }
+
+ /*
+ * Convert
+ * match (x, y)
+ * case (Zero, _) => Zero
+ * case (Suc(_), Zero) => x
+ * case (Suc(a), Suc(b)) => minus(a, b)
+ * To:
+ * match x
+ * case Zero => match y (originalToken)
+ * case _ => zero
+ * case Suc(_) => match y (AutoGeneratedToken)
+ * case Zero => x
+ * case Suc(a) => match y (AutoGeneratedToken)
+ * case (b) => minus(a,b)
+ */
+ void DesugarMatchStmtWithTupleExpression(MatchStmt me) {
+ // (x, y) is treated as a 2-tuple constructor
+ if (me.Source is DatatypeValue) {
+ var e = (DatatypeValue)me.Source;
+ if (e.Arguments.Count < 1) {
+ reporter.Error(MessageSource.Resolver, me.Tok, "match source tuple needs at least 1 argument");
+ } else {
+ Expression source = e.Arguments[0];
+ List<MatchCaseStmt> cases = new List<MatchCaseStmt>();
+ // only keep the token for the first appearance, use autogenerated for the rest, otherwise more than one hovertext
+ // will show up in the IDE.
+ bool keepOrigToken = true;
+ foreach (MatchCaseStmt mc in me.Cases) {
+ if (mc.CasePatterns == null || mc.CasePatterns.Count != e.Arguments.Count) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "case arguments count does not match source arguments count");
+ } else {
+ CasePattern cp = mc.CasePatterns[0];
+ List<CasePattern> patterns;
+ if (cp.Arguments != null) {
+ patterns = cp.Arguments;
+ } else {
+ patterns = new List<CasePattern>();
+ }
+
+ List<Statement> body = mc.Body;
+ for (int i = e.Arguments.Count; 1 <= --i; ) {
+ // others go into the body
+ body = CreateMatchCaseStmtBody(me.Tok, e.Arguments[i], mc.CasePatterns[i], body, keepOrigToken);
+ }
+ cases.Add(new MatchCaseStmt(cp.tok, cp.Id, patterns, body));
+ keepOrigToken = false;
}
}
- Contract.Assert(memberNamesUsed.Count + s.MissingCases.Count == dtd.Ctors.Count);
+ me.UpdateSource(source);
+ me.UpdateCases(cases);
}
- if (!s.IsGhost) {
- s.IsGhost = s.Cases.All(cs => cs.Body.All(ss => ss.IsGhost));
+ }
+ }
+
+ List<Statement> CreateMatchCaseStmtBody(Boogie.IToken tok, Expression source, CasePattern cp, List<Statement> body, bool keepToken) {
+ List<MatchCaseStmt> cases = new List<MatchCaseStmt>();
+ List<CasePattern> patterns;
+ if (cp.Var != null) {
+ var bv = cp.Var;
+ if (LocalVariable.HasWildcardName(bv)) {
+ return body;
+ } else {
+ patterns = new List<CasePattern>();
}
+ } else {
+ patterns = cp.Arguments;
+ }
+ cases.Add(new MatchCaseStmt(cp.tok, cp.Id, patterns, body));
+ if (!keepToken) {
+ AutoGeneratedTokenCloner cloner = new AutoGeneratedTokenCloner();
+ source = cloner.CloneExpr(source);
+ }
+ List<Statement> list = new List<Statement>();
+ // endTok??
+ list.Add(new MatchStmt(tok, tok, source, cases, false));
+ return list;
+ }
+
+
+ /*
+ * Convert
+ * match xs
+ * case Cons(y, Cons(z, zs)) => last(Cons(z, zs))
+ * case Cons(y, Nil) => y
+ * To
+ * match xs
+ * case Cons(y, ys) => match ys
+ * case Nil => y
+ * case Cons(z, zs) => last(ys)
+ */
+ void DesugarMatchCaseStmt(MatchStmt s, DatatypeDecl dtd, List<Tuple<CasePattern, BoundVar>> patterns, ICodeContext codeContext) {
+ Contract.Assert(dtd != null);
+ Dictionary<string, DatatypeCtor> ctors = datatypeCtors[dtd];
+ if (ctors == null) {
+ // there is no constructor, no need to desugar
+ return;
+ }
- } else if (stmt is SkeletonStatement) {
- var s = (SkeletonStatement)stmt;
- Error(s.Tok, "skeleton statements are allowed only in refining methods");
- // nevertheless, resolve the underlying statement; hey, why not
- if (s.S != null) {
- ResolveStatement(s.S, specContextOnly, codeContext);
+ Type type = new InferredTypeProxy();
+ string name = FreshTempVarName("_mc#", codeContext);
+ foreach (MatchCaseStmt mc in s.Cases) {
+ if (mc.Arguments != null) {
+ // already desugared. This happens during the second pass resolver after cloning.
+ Contract.Assert(mc.CasePatterns == null);
+ return;
+ }
+
+ BoundVar sourceVar = new BoundVar(new MatchCaseToken(s.Tok), name, type);
+ Contract.Assert(mc.Arguments == null);
+ Contract.Assert(mc.CasePatterns != null);
+ Contract.Assert(ctors != null);
+ DatatypeCtor ctor = null;
+
+ if (ctors.TryGetValue(mc.Id, out ctor)) {
+ scope.PushMarker();
+ foreach (CasePattern pat in mc.CasePatterns) {
+ FindDuplicateIdentifier(pat, ctors, true);
+ }
+ List<BoundVar> arguments = new List<BoundVar>();
+ foreach (CasePattern pat in mc.CasePatterns) {
+ if (pat.Var != null) {
+ BoundVar v = pat.Var;
+ arguments.Add(v);
+ } else {
+ DesugarMatchCasePattern(mc, pat, sourceVar);
+ patterns.Add(new Tuple<CasePattern, BoundVar>(pat, sourceVar));
+ arguments.Add(sourceVar);
+ }
+ }
+ mc.Arguments = arguments;
+ mc.CasePatterns = null;
+ scope.PopMarker();
+ }
+ }
+
+
+ List<MatchCaseStmt> newCases = new List<MatchCaseStmt>();
+
+ // need to consolidate the cases.
+ // Convert
+ // match xs
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Cons((z, zs) => body
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Nil => y
+ // into
+ // match xs
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Cons((z, zs) => body
+ // case Nil => y
+ bool thingsChanged = false;
+ Dictionary<string, MatchCaseStmt> caseMap = new Dictionary<string, MatchCaseStmt>();
+ List<MatchCaseStmt> mcWithWildCard = new List<MatchCaseStmt>();
+ foreach (MatchCaseStmt mc in s.Cases) {
+ // check each CasePattern to see if it has wildcard.
+ if (CaseExprHasWildCard(mc)) {
+ mcWithWildCard.Add(mc);
+ } else {
+ thingsChanged |= CombineMatchCaseStmt(mc, newCases, caseMap, codeContext);
+ }
+ }
+
+ foreach (MatchCaseStmt mc in mcWithWildCard) {
+ // now process with cases with wildcard
+ thingsChanged |= CombineMatchCaseStmt(mc, newCases, caseMap, codeContext);
+ }
+
+ if (thingsChanged) {
+ s.UpdateCases(newCases);
+ }
+ }
+
+ void FindDuplicateIdentifier(CasePattern pat, Dictionary<string, DatatypeCtor> ctors, bool topLevel) {
+ Contract.Assert(ctors != null);
+ DatatypeCtor ctor = null;
+ // Find the constructor in the given datatype
+ // If what was parsed was just an identifier, we will interpret it as a datatype constructor, if possible
+ if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy)) {
+ if (ctors.TryGetValue(pat.Id, out ctor)) {
+ pat.Ctor = ctor;
+ pat.Var = null;
+ }
+ }
+ if (pat.Var != null) {
+ BoundVar v = pat.Var;
+ if (topLevel) {
+ ScopePushAndReport(scope, v, "parameter");
+ } else {
+ // For cons(a, const(b, c)):
+ // this handles check to see if 'b' or 'c' is duplicate with 'a',
+ // the duplication check between 'b' and 'c' is handled in the desugared
+ // form (to avoid reporting the same error twice), that is why we don't
+ // push 'b' and 'c' onto the scope, only find.
+ if (scope.FindInCurrentScope(v.Name) != null) {
+ reporter.Error(MessageSource.Resolver, v, "Duplicate parameter name: {0}", v.Name);
+ }
}
} else {
- Contract.Assert(false); throw new cce.UnreachableException();
+ if (pat.Arguments != null) {
+ foreach (CasePattern cp in pat.Arguments) {
+ FindDuplicateIdentifier(cp, ctors, false);
+ }
+ }
+ }
+ }
+
+ void DesugarMatchCasePattern(MatchCaseStmt mc, CasePattern pat, BoundVar v) {
+ // convert
+ // case Cons(y, Cons(z, zs)) => body
+ // to
+ // case Cons(y, #mc#) => match #mc#
+ // case Cons(z, zs) => body
+
+ Expression source = new NameSegment(new AutoGeneratedToken(pat.tok), v.Name, null);
+ List<MatchCaseStmt> cases = new List<MatchCaseStmt>();
+ cases.Add(new MatchCaseStmt(pat.tok, pat.Id, pat.Arguments == null ? new List<CasePattern>() : pat.Arguments, mc.Body));
+ List<Statement> list = new List<Statement>();
+ // endTok??
+ list.Add(new MatchStmt(pat.tok, pat.tok, source, cases, false));
+ mc.UpdateBody(list);
+ }
+
+ bool CombineMatchCaseStmt(MatchCaseStmt mc, List<MatchCaseStmt> newCases, Dictionary<string, MatchCaseStmt> caseMap, ICodeContext codeContext) {
+ bool thingsChanged = false;
+ MatchCaseStmt old_mc;
+ if (caseMap.TryGetValue(mc.Id, out old_mc)) {
+ // already has a case with the same ctor, try to consolidate the body.
+ List<Statement> oldBody = old_mc.Body;
+ List<Statement> body = mc.Body;
+ if ((oldBody.Count == 1) && (oldBody[0] is MatchStmt)
+ && (body.Count == 1) && (body[0] is MatchStmt)) {
+ // both only have on statement and the statement is MatchStmt
+ if (SameMatchCaseStmt(old_mc, mc, codeContext)) {
+ MatchStmt old = (MatchStmt)old_mc.Body[0];
+ MatchStmt current = (MatchStmt)mc.Body[0];
+ foreach (MatchCaseStmt c in current.Cases) {
+ old.Cases.Add(c);
+ }
+ // add the token from mc to old_mc so the identifiers will show correctly in the IDE
+ List<BoundVar> arguments = new List<BoundVar>();
+ Contract.Assert(old_mc.Arguments.Count == mc.Arguments.Count);
+ for (int i = 0; i < old_mc.Arguments.Count; i++) {
+ var bv = old_mc.Arguments[i];
+ MatchCaseToken mcToken;
+ if (!(bv.tok is MatchCaseToken)) {
+ // create a MatchCaseToken
+ mcToken = new MatchCaseToken(bv.tok);
+ // clone the bv but with the MatchCaseToken
+ var bvNew = new BoundVar(mcToken, bv.Name, bv.Type);
+ bvNew.IsGhost = bv.IsGhost;
+ arguments.Add(bvNew);
+ } else {
+ mcToken = (MatchCaseToken)bv.tok;
+ arguments.Add(bv);
+ }
+ mcToken.AddVar(bv.tok, bv, true);
+ mcToken.AddVar(mc.Arguments[i].tok, mc.Arguments[i], true);
+ }
+ old_mc.Arguments = arguments;
+ thingsChanged = true;
+ }
+ } else {
+ // duplicate cases, do nothing for now. The error will be reported during resolving
+ }
+ } else {
+ // it is a new case.
+ newCases.Add(mc);
+ caseMap.Add(mc.Id, mc);
+ }
+ return thingsChanged;
+ }
+
+ bool SameMatchCaseStmt(MatchCaseStmt one, MatchCaseStmt other, ICodeContext codeContext) {
+ // this method is called after all the CasePattern in the match cases are converted
+ // into BoundVars.
+ Contract.Assert(one.CasePatterns == null && one.Arguments != null);
+ Contract.Assert(other.CasePatterns == null && other.Arguments != null);
+ // In order to combine the two match cases, the bodies need to be a MatchExpr and
+ // the arguments and the source of the body are the same.
+ // We do string equals since they should be in the same scope.
+ if (one.Arguments.Count != other.Arguments.Count) {
+ return false;
+ }
+ List<Statement> body1 = one.Body;
+ List<Statement> body2 = other.Body;
+ if ((body1.Count != 1) || (body2.Count != 1)) {
+ return false;
+ }
+ if (!(body1[0] is MatchStmt) || !(body2[0] is MatchStmt)) {
+ return false;
+ }
+ var source1 = ((MatchStmt)body1[0]).Source;
+ var source2 = ((MatchStmt)body2[0]).Source;
+ if (!(source1 is NameSegment) || !(source2 is NameSegment)) {
+ return false;
+ }
+ if (!((NameSegment)source1).Name.Equals(((NameSegment)source2).Name)) {
+ return false;
+ }
+ for (int i = 0; i < one.Arguments.Count; i++) {
+ BoundVar bv1 = one.Arguments[i];
+ BoundVar bv2 = other.Arguments[i];
+ if (!LocalVariable.HasWildcardName(bv1) && !LocalVariable.HasWildcardName(bv2)) {
+ if (!bv1.Name.Equals(bv2.Name)) {
+ // need to substitute bv2 with bv1 in the matchstmt body
+ // what if match body already has the bv?? need to make a new bv
+ Type type = new InferredTypeProxy();
+ string name = FreshTempVarName("_mc#", codeContext);
+ BoundVar bv = new BoundVar(new MatchCaseToken(one.tok), name, type);
+ ((MatchCaseToken)bv.tok).AddVar(bv1.tok, bv1, true);
+ ((MatchCaseToken)bv.tok).AddVar(bv2.tok, bv2, true);
+ SubstituteMatchCaseBoundVar(one, bv1, bv);
+ SubstituteMatchCaseBoundVar(other, bv2, bv);
+ }
+ }
+ }
+ return true;
+ }
+
+ void SubstituteMatchCaseBoundVar(MatchCaseStmt mc, BoundVar oldBv, BoundVar newBv) {
+ List<BoundVar> arguments = new List<BoundVar>();
+ for (int i = 0; i < mc.Arguments.Count; i++) {
+ BoundVar bv = mc.Arguments[i];
+ if (bv == oldBv) {
+ arguments.Add(newBv);
+ } else {
+ arguments.Add(bv);
+ }
}
+ mc.Arguments = arguments;
+
+ // substitue the oldBv with newBv in the body
+ MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(oldBv, newBv);
+ List<Statement> list = new List<Statement>();
+ foreach (Statement ss in mc.Body) {
+ Statement clone = cloner.CloneStmt(ss);
+ list.Add(clone);
+ }
+ mc.UpdateBody(list);
}
void FillInDefaultLoopDecreases(LoopStmt loopStmt, Expression guard, List<Expression> theDecreases, ICallable enclosingMethod) {
@@ -5346,35 +6598,24 @@ namespace Microsoft.Dafny
loopStmt.InferredDecreases = true;
}
if (loopStmt.InferredDecreases) {
- string s = "decreases ";
- if (theDecreases.Count != 0) {
- string sep = "";
- foreach (var d in theDecreases) {
- s += sep + Printer.ExprToString(d);
- sep = ", ";
- }
- }
- s += ";"; // always terminate with a semi-colon, even in the case of an empty decreases clause
- ReportAdditionalInformation(loopStmt.Tok, s, loopStmt.Tok.val.Length);
+ string s = "decreases " + Util.Comma(", ", theDecreases, Printer.ExprToString);
+ reporter.Info(MessageSource.Resolver, loopStmt.Tok, s);
}
}
- private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, bool specContextOnly, ICodeContext codeContext) {
+ private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, ICodeContext codeContext) {
Contract.Requires(codeContext != null);
// First, resolve all LHS's and expression-looking RHS's.
- int errorCountBeforeCheckingLhs = ErrorCount;
+ int errorCountBeforeCheckingLhs = reporter.Count(ErrorLevel.Error);
var update = s as UpdateStmt;
var lhsNameSet = new HashSet<string>(); // used to check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification)
foreach (var lhs in s.Lhss) {
- var ec = ErrorCount;
- ResolveExpression(lhs, new ResolveOpts(codeContext, true, specContextOnly));
- if (ec == ErrorCount) {
- if (update == null && specContextOnly && !AssignStmt.LhsIsToGhost(lhs) && !codeContext.IsGhost) {
- Error(lhs, "cannot assign to non-ghost variable in a ghost context");
- }
+ var ec = reporter.Count(ErrorLevel.Error);
+ ResolveExpression(lhs, new ResolveOpts(codeContext, true));
+ if (ec == reporter.Count(ErrorLevel.Error)) {
if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) {
- Error(lhs, "cannot assign to a range of array elements (try the 'forall' statement)");
+ reporter.Error(MessageSource.Resolver, lhs, "cannot assign to a range of array elements (try the 'forall' statement)");
}
}
}
@@ -5382,18 +6623,18 @@ namespace Microsoft.Dafny
// Resolve RHSs
if (update == null) {
var suchThat = (AssignSuchThatStmt)s; // this is the other possible subclass
- ResolveAssignSuchThatStmt(suchThat, specContextOnly, codeContext);
+ ResolveAssignSuchThatStmt(suchThat, codeContext);
} else {
- ResolveUpdateStmt(update, specContextOnly, codeContext, errorCountBeforeCheckingLhs);
+ ResolveUpdateStmt(update, codeContext, errorCountBeforeCheckingLhs);
}
- ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true, true));
+ ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true));
}
/// <summary>
/// Resolve the RHSs and entire UpdateStmt (LHSs should already have been checked by the caller).
/// errorCountBeforeCheckingLhs is passed in so that this method can determined if any resolution errors were found during
/// LHS or RHS checking, because only if no errors were found is update.ResolvedStmt changed.
/// </summary>
- private void ResolveUpdateStmt(UpdateStmt update, bool specContextOnly, ICodeContext codeContext, int errorCountBeforeCheckingLhs) {
+ private void ResolveUpdateStmt(UpdateStmt update, ICodeContext codeContext, int errorCountBeforeCheckingLhs) {
Contract.Requires(update != null);
Contract.Requires(codeContext != null);
IToken firstEffectfulRhs = null;
@@ -5403,7 +6644,7 @@ namespace Microsoft.Dafny
bool isEffectful;
if (rhs is TypeRhs) {
var tr = (TypeRhs)rhs;
- ResolveTypeRhs(tr, update, specContextOnly, codeContext);
+ ResolveTypeRhs(tr, update, codeContext);
isEffectful = tr.InitCall != null;
} else if (rhs is HavocRhs) {
isEffectful = false;
@@ -5411,17 +6652,11 @@ namespace Microsoft.Dafny
var er = (ExprRhs)rhs;
if (er.Expr is ApplySuffix) {
var a = (ApplySuffix)er.Expr;
- // Note, in the following line, the dontCareAboutCompilation could be more precise. It could be computed as in the else
- // branch if the ApplySuffix is really just the RHS of an assignment. However, if "update" is really a call statement,
- // then we should not let the LHS influence the call to ResolveApplySuffix. Unfortunately, we don't know which case
- // we're in until ResolveApplySuffix has returned (where a non-null cRhs indicates that "update" is a call statement).
- // So, we'll be conservative and will simply pass in specContextOnly here.
- var cRhs = ResolveApplySuffix(a, new ResolveOpts(codeContext, true, specContextOnly/*see note on previous line*/), true);
+ var cRhs = ResolveApplySuffix(a, new ResolveOpts(codeContext, true), true);
isEffectful = cRhs != null;
methodCallInfo = methodCallInfo ?? cRhs;
} else {
- var dontCareAboutCompilation = specContextOnly || (j < update.Lhss.Count && AssignStmt.LhsIsToGhost(update.Lhss[j]));
- ResolveExpression(er.Expr, new ResolveOpts(codeContext, true, dontCareAboutCompilation));
+ ResolveExpression(er.Expr, new ResolveOpts(codeContext, true));
isEffectful = false;
}
}
@@ -5435,10 +6670,10 @@ namespace Microsoft.Dafny
if (firstEffectfulRhs == null) {
if (update.Lhss.Count == 0) {
Contract.Assert(update.Rhss.Count == 1); // guaranteed by the parser
- Error(update, "expected method call, found expression");
+ reporter.Error(MessageSource.Resolver, update, "expected method call, found expression");
} else if (update.Lhss.Count != update.Rhss.Count) {
- Error(update, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", update.Lhss.Count, update.Rhss.Count);
- } else if (ErrorCount == errorCountBeforeCheckingLhs) {
+ reporter.Error(MessageSource.Resolver, update, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", update.Lhss.Count, update.Rhss.Count);
+ } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {
// add the statements here in a sequence, but don't use that sequence later for translation (instead, should translate properly as multi-assignment)
for (int i = 0; i < update.Lhss.Count; i++) {
var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[i].Resolved, update.Rhss[i]);
@@ -5448,19 +6683,19 @@ namespace Microsoft.Dafny
} else if (update.CanMutateKnownState) {
if (1 < update.Rhss.Count) {
- Error(firstEffectfulRhs, "cannot have effectful parameter in multi-return statement.");
+ reporter.Error(MessageSource.Resolver, firstEffectfulRhs, "cannot have effectful parameter in multi-return statement.");
} else { // it might be ok, if it is a TypeRhs
Contract.Assert(update.Rhss.Count == 1);
if (methodCallInfo != null) {
- Error(methodCallInfo.Tok, "cannot have method call in return statement.");
+ reporter.Error(MessageSource.Resolver, methodCallInfo.Tok, "cannot have method call in return statement.");
} else {
// we have a TypeRhs
Contract.Assert(update.Rhss[0] is TypeRhs);
var tr = (TypeRhs)update.Rhss[0];
Contract.Assert(tr.InitCall != null); // there were effects, so this must have been a call.
if (tr.CanAffectPreviouslyKnownExpressions) {
- Error(tr.Tok, "can only have initialization methods which modify at most 'this'.");
- } else if (ErrorCount == errorCountBeforeCheckingLhs) {
+ reporter.Error(MessageSource.Resolver, tr.Tok, "can only have initialization methods which modify at most 'this'.");
+ } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {
var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, tr);
update.ResolvedStatements.Add(a);
}
@@ -5470,17 +6705,17 @@ namespace Microsoft.Dafny
} else {
// if there was an effectful RHS, that must be the only RHS
if (update.Rhss.Count != 1) {
- Error(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS");
+ reporter.Error(MessageSource.Resolver, firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS");
} else if (methodCallInfo == null) {
// must be a single TypeRhs
if (update.Lhss.Count != 1) {
Contract.Assert(2 <= update.Lhss.Count); // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs)
- Error(update.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", update.Lhss.Count, update.Rhss.Count);
- } else if (ErrorCount == errorCountBeforeCheckingLhs) {
+ reporter.Error(MessageSource.Resolver, update.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", update.Lhss.Count, update.Rhss.Count);
+ } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {
var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, update.Rhss[0]);
update.ResolvedStatements.Add(a);
}
- } else if (ErrorCount == errorCountBeforeCheckingLhs) {
+ } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {
// a call statement
var resolvedLhss = new List<Expression>();
foreach (var ll in update.Lhss) {
@@ -5492,12 +6727,11 @@ namespace Microsoft.Dafny
}
foreach (var a in update.ResolvedStatements) {
- ResolveStatement(a, specContextOnly, codeContext);
+ ResolveStatement(a, codeContext);
}
- update.IsGhost = update.ResolvedStatements.TrueForAll(ss => ss.IsGhost);
}
- private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, bool specContextOnly, ICodeContext codeContext) {
+ private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, ICodeContext codeContext) {
Contract.Requires(s != null);
Contract.Requires(codeContext != null);
@@ -5507,80 +6741,57 @@ namespace Microsoft.Dafny
foreach (var lhs in s.Lhss) {
var ide = lhs.Resolved as IdentifierExpr;
if (ide == null) {
- Error(lhs, "the assign-such-that statement currently only supports local-variable LHSs");
+ reporter.Error(MessageSource.Resolver, lhs, "the assign-such-that statement currently only supports local-variable LHSs");
} else {
varLhss.Add(ide.Var);
}
}
}
- s.IsGhost = s.Lhss.TrueForAll(AssignStmt.LhsIsToGhost);
- var ec = ErrorCount;
- ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, specContextOnly));
- if (ec == ErrorCount && !s.IsGhost && s.AssumeToken == null && !specContextOnly) {
- CheckIsNonGhost(s.Expr);
-
- var missingBounds = new List<IVariable>();
- CheckTypeInference(s.Expr); // we need to resolve operators before the call to DiscoverBoundsAux
- var allBounds = DiscoverBoundsAux(s.Tok, varLhss, s.Expr, true, true, true, missingBounds);
- if (missingBounds.Count != 0) {
- s.MissingBounds = missingBounds; // so that an error message can be produced during compilation
- } else {
- Contract.Assert(allBounds != null);
- s.Bounds = new List<ComprehensionExpr.BoundedPool>();
- foreach (var pair in allBounds) {
- Contract.Assert(1 <= pair.Item2.Count);
- // TODO: The following could be improved by picking the bound that is most likely to give rise to an efficient compiled program
- s.Bounds.Add(pair.Item2[0]);
- }
- }
- }
+ var ec = reporter.Count(ErrorLevel.Error);
+ ResolveExpression(s.Expr, new ResolveOpts(codeContext, true));
+ ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type);
}
- bool ResolveAlternatives(List<GuardedAlternative> alternatives, bool specContextOnly, AlternativeLoopStmt loopToCatchBreaks, ICodeContext codeContext) {
+ void ResolveAlternatives(List<GuardedAlternative> alternatives, AlternativeLoopStmt loopToCatchBreaks, ICodeContext codeContext) {
Contract.Requires(alternatives != null);
Contract.Requires(codeContext != null);
- bool isGhost = specContextOnly;
- // first, resolve the guards, which tells us whether or not the entire statement is a ghost statement
+ // first, resolve the guards
foreach (var alternative in alternatives) {
- int prevErrorCount = ErrorCount;
- ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true, specContextOnly));
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
+ ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true));
Contract.Assert(alternative.Guard.Type != null); // follows from postcondition of ResolveExpression
- bool successfullyResolved = ErrorCount == prevErrorCount;
- if (!UnifyTypes(alternative.Guard.Type, Type.Bool)) {
- Error(alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type);
- }
- if (!specContextOnly && successfullyResolved) {
- isGhost = isGhost || UsesSpecFeatures(alternative.Guard);
- }
+ bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount;
+ ConstrainTypes(alternative.Guard.Type, Type.Bool, alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type);
}
if (loopToCatchBreaks != null) {
loopStack.Add(loopToCatchBreaks); // push
- if (loopToCatchBreaks.Labels == null) { // otherwise, "loopToCatchBreak" is already in "inSpecOnlyContext" map
- inSpecOnlyContext.Add(loopToCatchBreaks, specContextOnly);
- }
}
foreach (var alternative in alternatives) {
scope.PushMarker();
+ if (alternative.IsExistentialGuard) {
+ var exists = (ExistsExpr)alternative.Guard;
+ foreach (var v in exists.BoundVars) {
+ ScopePushAndReport(scope, v, "bound-variable");
+ }
+ }
foreach (Statement ss in alternative.Body) {
- ResolveStatement(ss, isGhost, codeContext);
+ ResolveStatement(ss, codeContext);
}
scope.PopMarker();
}
if (loopToCatchBreaks != null) {
loopStack.RemoveAt(loopStack.Count - 1); // pop
}
-
- return isGhost;
}
/// <summary>
/// Resolves the given call statement.
/// Assumes all LHSs have already been resolved (and checked for mutability).
/// </summary>
- void ResolveCallStmt(CallStmt s, bool specContextOnly, ICodeContext codeContext, Type receiverType) {
+ void ResolveCallStmt(CallStmt s, ICodeContext codeContext, Type receiverType) {
Contract.Requires(s != null);
Contract.Requires(codeContext != null);
bool isInitCall = receiverType != null;
@@ -5588,11 +6799,7 @@ namespace Microsoft.Dafny
var callee = s.Method;
Contract.Assert(callee != null); // follows from the invariant of CallStmt
if (!isInitCall && callee is Constructor) {
- Error(s, "a constructor is allowed to be called only when an object is being allocated");
- }
- s.IsGhost = callee.IsGhost;
- if (specContextOnly && !callee.IsGhost) {
- Error(s, "only ghost methods can be called from this context");
+ reporter.Error(MessageSource.Resolver, s, "a constructor is allowed to be called only when an object is being allocated");
}
// resolve left-hand sides
@@ -5600,79 +6807,46 @@ namespace Microsoft.Dafny
Contract.Assume(lhs.Type != null); // a sanity check that LHSs have already been resolved
}
// resolve arguments
- if (!s.IsGhost && s.Receiver.WasResolved()) {
- CheckIsNonGhost(s.Receiver);
- }
int j = 0;
foreach (Expression e in s.Args) {
- bool allowGhost = s.IsGhost || callee.Ins.Count <= j || callee.Ins[j].IsGhost;
- var ec = ErrorCount;
- ResolveExpression(e, new ResolveOpts(codeContext, true, allowGhost));
- if (ec == ErrorCount && !allowGhost) {
- CheckIsNonGhost(e);
- }
+ ResolveExpression(e, new ResolveOpts(codeContext, true));
j++;
}
if (callee.Ins.Count != s.Args.Count) {
- Error(s, "wrong number of method arguments (got {0}, expected {1})", s.Args.Count, callee.Ins.Count);
+ reporter.Error(MessageSource.Resolver, s, "wrong number of method arguments (got {0}, expected {1})", s.Args.Count, callee.Ins.Count);
} else if (callee.Outs.Count != s.Lhs.Count) {
if (isInitCall) {
- Error(s, "a method called as an initialization method must not have any result arguments");
+ reporter.Error(MessageSource.Resolver, s, "a method called as an initialization method must not have any result arguments");
} else {
- Error(s, "wrong number of method result arguments (got {0}, expected {1})", s.Lhs.Count, callee.Outs.Count);
+ reporter.Error(MessageSource.Resolver, s, "wrong number of method result arguments (got {0}, expected {1})", s.Lhs.Count, callee.Outs.Count);
}
} else {
if (isInitCall) {
if (callee.IsStatic) {
- Error(s.Tok, "a method called as an initialization method must not be 'static'");
+ reporter.Error(MessageSource.Resolver, s.Tok, "a method called as an initialization method must not be 'static'");
}
} else if (!callee.IsStatic) {
if (!scope.AllowInstance && s.Receiver is ThisExpr) {
// The call really needs an instance, but that instance is given as 'this', which is not
// available in this context. For more details, see comment in the resolution of a
// FunctionCallExpr.
- Error(s.Receiver, "'this' is not allowed in a 'static' context");
+ reporter.Error(MessageSource.Resolver, s.Receiver, "'this' is not allowed in a 'static' context");
} else if (s.Receiver is StaticReceiverExpr) {
- Error(s.Receiver, "call to instance method requires an instance");
+ reporter.Error(MessageSource.Resolver, s.Receiver, "call to instance method requires an instance");
}
}
// type check the arguments
for (int i = 0; i < callee.Ins.Count; i++) {
Type st = SubstType(callee.Ins[i].Type, s.MethodSelect.TypeArgumentSubstitutions());
- if (!UnifyTypes(cce.NonNull(s.Args[i].Type), st)) {
- Error(s, "incorrect type of method in-parameter {0} (expected {1}, got {2})", i, st, s.Args[i].Type);
- }
+ ConstrainTypes(s.Args[i].Type, st, s, "incorrect type of method in-parameter {0} (expected {1}, got {2})", i, st, s.Args[i].Type);
}
for (int i = 0; i < callee.Outs.Count; i++) {
Type st = SubstType(callee.Outs[i].Type, s.MethodSelect.TypeArgumentSubstitutions());
var lhs = s.Lhs[i];
- if (!UnifyTypes(cce.NonNull(lhs.Type), st)) {
- Error(s, "incorrect type of method out-parameter {0} (expected {1}, got {2})", i, st, lhs.Type);
+ if (!ConstrainTypes(lhs.Type, st, s, "incorrect type of method out-parameter {0} (expected {1}, got {2})", i, st, lhs.Type)) {
} else {
var resolvedLhs = lhs.Resolved;
- if (!specContextOnly && (s.IsGhost || callee.Outs[i].IsGhost)) {
- // LHS must denote a ghost
- if (resolvedLhs is IdentifierExpr) {
- var ll = (IdentifierExpr)resolvedLhs;
- if (!ll.Var.IsGhost) {
- if (ll is AutoGhostIdentifierExpr && ll.Var is LocalVariable) {
- // the variable was actually declared in this statement, so auto-declare it as ghost
- ((LocalVariable)ll.Var).MakeGhost();
- } else {
- Error(s, "actual out-parameter {0} is required to be a ghost variable", i);
- }
- }
- } else if (resolvedLhs is MemberSelectExpr) {
- var ll = (MemberSelectExpr)resolvedLhs;
- if (!ll.Member.IsGhost) {
- Error(s, "actual out-parameter {0} is required to be a ghost field", i);
- }
- } else {
- // this is an array update, and arrays are always non-ghost
- Error(s, "actual out-parameter {0} is required to be a ghost variable", i);
- }
- }
// LHS must denote a mutable field.
CheckIsLvalue(resolvedLhs, codeContext);
}
@@ -5697,7 +6871,7 @@ namespace Microsoft.Dafny
}
}
if (Contract.Exists(callee.Decreases.Expressions, e => e is WildcardExpr) && !codeContext.AllowsNontermination) {
- Error(s.Tok, "a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating");
+ reporter.Error(MessageSource.Resolver, s.Tok, "a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating");
}
}
@@ -5712,30 +6886,28 @@ namespace Microsoft.Dafny
if (lhs is IdentifierExpr) {
var ll = (IdentifierExpr)lhs;
if (!ll.Var.IsMutable) {
- Error(lhs, "LHS of assignment must denote a mutable variable");
+ reporter.Error(MessageSource.Resolver, lhs, "LHS of assignment must denote a mutable variable");
}
} else if (lhs is MemberSelectExpr) {
var ll = (MemberSelectExpr)lhs;
var field = ll.Member as Field;
if (field == null || !field.IsUserMutable) {
- Error(lhs, "LHS of assignment must denote a mutable field");
+ reporter.Error(MessageSource.Resolver, lhs, "LHS of assignment must denote a mutable field");
}
} else if (lhs is SeqSelectExpr) {
var ll = (SeqSelectExpr)lhs;
- if (!UnifyTypes(ll.Seq.Type, ResolvedArrayType(ll.Seq.tok, 1, new InferredTypeProxy(), codeContext))) {
- Error(ll.Seq, "LHS of array assignment must denote an array element (found {0})", ll.Seq.Type);
- }
+ ConstrainTypes(ll.Seq.Type, ResolvedArrayType(ll.Seq.tok, 1, new InferredTypeProxy(), codeContext), ll.Seq, "LHS of array assignment must denote an array element (found {0})", ll.Seq.Type);
if (!ll.SelectOne) {
- Error(ll.Seq, "cannot assign to a range of array elements (try the 'forall' statement)");
+ reporter.Error(MessageSource.Resolver, ll.Seq, "cannot assign to a range of array elements (try the 'forall' statement)");
}
} else if (lhs is MultiSelectExpr) {
// nothing to check; this can only denote an array element
} else {
- Error(lhs, "LHS of assignment must denote a mutable variable or field");
+ reporter.Error(MessageSource.Resolver, lhs, "LHS of assignment must denote a mutable variable or field");
}
}
- void ResolveBlockStatement(BlockStmt blockStmt, bool specContextOnly, ICodeContext codeContext) {
+ void ResolveBlockStatement(BlockStmt blockStmt, ICodeContext codeContext) {
Contract.Requires(blockStmt != null);
Contract.Requires(codeContext != null);
@@ -5747,18 +6919,15 @@ namespace Microsoft.Dafny
Contract.Assert(lnode.Name != null); // LabelNode's with .Label==null are added only during resolution of the break statements with 'stmt' as their target, which hasn't happened yet
var prev = labeledStatements.Find(lnode.Name);
if (prev == ss) {
- Error(lnode.Tok, "duplicate label");
+ reporter.Error(MessageSource.Resolver, lnode.Tok, "duplicate label");
} else if (prev != null) {
- Error(lnode.Tok, "label shadows an enclosing label");
+ reporter.Error(MessageSource.Resolver, lnode.Tok, "label shadows an enclosing label");
} else {
- bool b = labeledStatements.Push(lnode.Name, ss);
- Contract.Assert(b); // since we just checked for duplicates, we expect the Push to succeed
- if (l == ss.Labels) { // add it only once
- inSpecOnlyContext.Add(ss, specContextOnly);
- }
+ var r = labeledStatements.Push(lnode.Name, ss);
+ Contract.Assert(r == Scope<Statement>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed
}
}
- ResolveStatement(ss, specContextOnly, codeContext);
+ ResolveStatement(ss, codeContext);
labeledStatements.PopMarker();
}
}
@@ -5771,13 +6940,13 @@ namespace Microsoft.Dafny
if (stmt is PredicateStmt) {
// cool
} else if (stmt is PrintStmt) {
- Error(stmt, "print statement is not allowed inside a forall statement");
+ reporter.Error(MessageSource.Resolver, stmt, "print statement is not allowed inside a forall statement");
} else if (stmt is BreakStmt) {
// this case is checked already in the first pass through the forall-statement body, by doing so from an empty set of labeled statements and resetting the loop-stack
} else if (stmt is ReturnStmt) {
- Error(stmt, "return statement is not allowed inside a forall statement");
+ reporter.Error(MessageSource.Resolver, stmt, "return statement is not allowed inside a forall statement");
} else if (stmt is YieldStmt) {
- Error(stmt, "yield statement is not allowed inside a forall statement");
+ reporter.Error(MessageSource.Resolver, stmt, "yield statement is not allowed inside a forall statement");
} else if (stmt is AssignSuchThatStmt) {
var s = (AssignSuchThatStmt)stmt;
foreach (var lhs in s.Lhss) {
@@ -5793,15 +6962,17 @@ namespace Microsoft.Dafny
if (s.Update != null) {
CheckForallStatementBodyRestrictions(s.Update, kind);
}
+ } else if (stmt is LetStmt) {
+ // Are we fine?
} else if (stmt is AssignStmt) {
var s = (AssignStmt)stmt;
CheckForallStatementBodyLhs(s.Tok, s.Lhs.Resolved, kind);
var rhs = s.Rhs; // ExprRhs and HavocRhs are fine, but TypeRhs is not
if (rhs is TypeRhs) {
if (kind == ForallStmt.ParBodyKind.Assign) {
- Error(rhs.Tok, "new allocation not supported in forall statements");
+ reporter.Error(MessageSource.Resolver, rhs.Tok, "new allocation not supported in forall statements");
} else {
- Error(rhs.Tok, "new allocation not allowed in ghost context");
+ reporter.Error(MessageSource.Resolver, rhs.Tok, "new allocation not allowed in ghost context");
}
}
} else if (stmt is CallStmt) {
@@ -5810,14 +6981,14 @@ namespace Microsoft.Dafny
var idExpr = lhs as IdentifierExpr;
if (idExpr != null) {
if (scope.ContainsDecl(idExpr.Var)) {
- Error(stmt, "body of forall statement is attempting to update a variable declared outside the forall statement");
+ reporter.Error(MessageSource.Resolver, stmt, "body of forall statement is attempting to update a variable declared outside the forall statement");
}
} else {
- Error(stmt, "the body of the enclosing forall statement is not allowed to update heap locations");
+ reporter.Error(MessageSource.Resolver, stmt, "the body of the enclosing forall statement is not allowed to update heap locations");
}
}
if (s.Method.Mod.Expressions.Count != 0) {
- Error(stmt, "the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause");
+ reporter.Error(MessageSource.Resolver, stmt, "the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause");
}
if (!s.Method.IsGhost) {
// The reason for this restriction is that the compiler is going to omit the forall statement altogether--it has
@@ -5825,7 +6996,7 @@ namespace Microsoft.Dafny
// a method that prints something, all calls to non-ghost methods are disallowed. (Note, if this restriction
// is somehow lifted in the future, then it is still necessary to enforce s.Method.Mod.Expressions.Count != 0 for
// calls to non-ghost methods.)
- Error(s, "the body of the enclosing forall statement is not allowed to call non-ghost methods");
+ reporter.Error(MessageSource.Resolver, s, "the body of the enclosing forall statement is not allowed to call non-ghost methods");
}
} else if (stmt is BlockStmt) {
@@ -5869,7 +7040,7 @@ namespace Microsoft.Dafny
var s = (ForallStmt)stmt;
switch (s.Kind) {
case ForallStmt.ParBodyKind.Assign:
- Error(stmt, "a forall statement with heap updates is not allowed inside the body of another forall statement");
+ reporter.Error(MessageSource.Resolver, stmt, "a forall statement with heap updates is not allowed inside the body of another forall statement");
break;
case ForallStmt.ParBodyKind.Call:
case ForallStmt.ParBodyKind.Proof:
@@ -5900,10 +7071,10 @@ namespace Microsoft.Dafny
var idExpr = lhs as IdentifierExpr;
if (idExpr != null) {
if (scope.ContainsDecl(idExpr.Var)) {
- Error(tok, "body of forall statement is attempting to update a variable declared outside the forall statement");
+ reporter.Error(MessageSource.Resolver, tok, "body of forall statement is attempting to update a variable declared outside the forall statement");
}
} else if (kind != ForallStmt.ParBodyKind.Assign) {
- Error(tok, "the body of the enclosing forall statement is not allowed to update heap locations");
+ reporter.Error(MessageSource.Resolver, tok, "the body of the enclosing forall statement is not allowed to update heap locations");
}
}
@@ -5911,8 +7082,9 @@ namespace Microsoft.Dafny
/// Check that a statment is a valid hint for a calculation.
/// ToDo: generalize the part for compound statements to take a delegate?
/// </summary>
- public void CheckHintRestrictions(Statement stmt) {
+ public void CheckHintRestrictions(Statement stmt, ISet<LocalVariable> localsAllowedInUpdates) {
Contract.Requires(stmt != null);
+ Contract.Requires(localsAllowedInUpdates != null);
if (stmt is PredicateStmt) {
// cool
} else if (stmt is PrintStmt) {
@@ -5920,69 +7092,71 @@ namespace Microsoft.Dafny
} else if (stmt is BreakStmt) {
// already checked while resolving hints
} else if (stmt is ReturnStmt) {
- Error(stmt, "return statement is not allowed inside a hint");
+ reporter.Error(MessageSource.Resolver, stmt, "return statement is not allowed inside a hint");
} else if (stmt is YieldStmt) {
- Error(stmt, "yield statement is not allowed inside a hint");
+ reporter.Error(MessageSource.Resolver, stmt, "yield statement is not allowed inside a hint");
} else if (stmt is AssignSuchThatStmt) {
var s = (AssignSuchThatStmt)stmt;
foreach (var lhs in s.Lhss) {
- CheckHintLhs(s.Tok, lhs.Resolved);
+ CheckHintLhs(s.Tok, lhs.Resolved, localsAllowedInUpdates);
}
} else if (stmt is AssignStmt) {
var s = (AssignStmt)stmt;
- CheckHintLhs(s.Tok, s.Lhs.Resolved);
+ CheckHintLhs(s.Tok, s.Lhs.Resolved, localsAllowedInUpdates);
} else if (stmt is CallStmt) {
var s = (CallStmt)stmt;
if (s.Method.Mod.Expressions.Count != 0) {
- Error(stmt, "calls to methods with side-effects are not allowed inside a hint");
+ reporter.Error(MessageSource.Resolver, stmt, "calls to methods with side-effects are not allowed inside a hint");
}
} else if (stmt is UpdateStmt) {
var s = (UpdateStmt)stmt;
foreach (var ss in s.ResolvedStatements) {
- CheckHintRestrictions(ss);
+ CheckHintRestrictions(ss, localsAllowedInUpdates);
}
} else if (stmt is VarDeclStmt) {
var s = (VarDeclStmt)stmt;
+ s.Locals.Iter(local => localsAllowedInUpdates.Add(local));
if (s.Update != null) {
- CheckHintRestrictions(s.Update);
+ CheckHintRestrictions(s.Update, localsAllowedInUpdates);
}
+ } else if (stmt is LetStmt) {
+ // Are we fine?
} else if (stmt is BlockStmt) {
var s = (BlockStmt)stmt;
- scope.PushMarker();
+ var newScopeForLocals = new HashSet<LocalVariable>(localsAllowedInUpdates);
foreach (var ss in s.Body) {
- CheckHintRestrictions(ss);
+ CheckHintRestrictions(ss, newScopeForLocals);
}
- scope.PopMarker();
} else if (stmt is IfStmt) {
var s = (IfStmt)stmt;
- CheckHintRestrictions(s.Thn);
+ CheckHintRestrictions(s.Thn, localsAllowedInUpdates);
if (s.Els != null) {
- CheckHintRestrictions(s.Els);
+ CheckHintRestrictions(s.Els, localsAllowedInUpdates);
}
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
foreach (var alt in s.Alternatives) {
foreach (var ss in alt.Body) {
- CheckHintRestrictions(ss);
+ CheckHintRestrictions(ss, localsAllowedInUpdates);
}
}
} else if (stmt is WhileStmt) {
var s = (WhileStmt)stmt;
if (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0) {
- Error(s.Mod.Expressions[0].tok, "a while statement used inside a hint is not allowed to have a modifies clause");
+ reporter.Error(MessageSource.Resolver, s.Mod.Expressions[0].tok, "a while statement used inside a hint is not allowed to have a modifies clause");
}
if (s.Body != null) {
- CheckHintRestrictions(s.Body);
+ CheckHintRestrictions(s.Body, localsAllowedInUpdates);
}
} else if (stmt is AlternativeLoopStmt) {
var s = (AlternativeLoopStmt)stmt;
foreach (var alt in s.Alternatives) {
foreach (var ss in alt.Body) {
- CheckHintRestrictions(ss);
+ CheckHintRestrictions(ss, localsAllowedInUpdates);
}
}
@@ -5990,7 +7164,7 @@ namespace Microsoft.Dafny
var s = (ForallStmt)stmt;
switch (s.Kind) {
case ForallStmt.ParBodyKind.Assign:
- Error(stmt, "a forall statement with heap updates is not allowed inside a hint");
+ reporter.Error(MessageSource.Resolver, stmt, "a forall statement with heap updates is not allowed inside a hint");
break;
case ForallStmt.ParBodyKind.Call:
case ForallStmt.ParBodyKind.Proof:
@@ -6004,14 +7178,14 @@ namespace Microsoft.Dafny
} else if (stmt is CalcStmt) {
var s = (CalcStmt)stmt;
foreach (var h in s.Hints) {
- CheckHintRestrictions(h);
+ CheckHintRestrictions(h, new HashSet<LocalVariable>());
}
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
foreach (var kase in s.Cases) {
foreach (var ss in kase.Body) {
- CheckHintRestrictions(ss);
+ CheckHintRestrictions(ss, localsAllowedInUpdates);
}
}
@@ -6020,25 +7194,24 @@ namespace Microsoft.Dafny
}
}
- void CheckHintLhs(IToken tok, Expression lhs) {
+ void CheckHintLhs(IToken tok, Expression lhs, ISet<LocalVariable> localsAllowedInUpdates) {
+ Contract.Requires(tok != null);
+ Contract.Requires(lhs != null);
+ Contract.Requires(localsAllowedInUpdates != null);
var idExpr = lhs as IdentifierExpr;
if (idExpr == null) {
- Error(tok, "a hint is not allowed to update heap locations");
- } else if (scope.ContainsDecl(idExpr.Var)) {
- Error(tok, "a hint is not allowed to update a variable declared outside the hint");
+ reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update heap locations");
+ } else if (!localsAllowedInUpdates.Contains(idExpr.Var)) {
+ reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update a variable declared outside the hint");
}
}
- Type ResolveTypeRhs(TypeRhs rr, Statement stmt, bool specContextOnly, ICodeContext codeContext) {
+ Type ResolveTypeRhs(TypeRhs rr, Statement stmt, ICodeContext codeContext) {
Contract.Requires(rr != null);
Contract.Requires(stmt != null);
Contract.Requires(codeContext != null);
Contract.Ensures(Contract.Result<Type>() != null);
- // "new" is not allowed in ghost contexts
- if (specContextOnly) {
- Error(rr.Tok, "'new' is not allowed in ghost contexts");
- }
if (rr.Type == null) {
if (rr.ArrayDimensions != null) {
// ---------- new T[EE]
@@ -6048,9 +7221,7 @@ namespace Microsoft.Dafny
foreach (Expression dim in rr.ArrayDimensions) {
Contract.Assert(dim != null);
ResolveExpression(dim, new ResolveOpts(codeContext, true));
- if (!UnifyTypes(dim.Type, new OperationTypeProxy(true, false, false, false, false))) {
- Error(stmt, "new must use an integer-based expression for the array size (got {0} for index {1})", dim.Type, i);
- }
+ ConstrainTypes(dim.Type, new OperationTypeProxy(true, false, false, false, false, false), stmt, "new must use an integer-based expression for the array size (got {0} for index {1})", dim.Type, i);
i++;
}
rr.Type = ResolvedArrayType(stmt.Tok, rr.ArrayDimensions.Count, rr.EType, codeContext);
@@ -6059,7 +7230,7 @@ namespace Microsoft.Dafny
if (rr.Arguments == null) {
ResolveType(stmt.Tok, rr.EType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
if (!rr.EType.IsRefType) {
- Error(stmt, "new can be applied only to reference types (got {0})", rr.EType);
+ reporter.Error(MessageSource.Resolver, stmt, "new can be applied only to reference types (got {0})", rr.EType);
}
} else {
string initCallName = null;
@@ -6082,28 +7253,28 @@ namespace Microsoft.Dafny
initCallTok = rr.Tok;
}
if (!rr.EType.IsRefType) {
- Error(stmt, "new can be applied only to reference types (got {0})", rr.EType);
+ reporter.Error(MessageSource.Resolver, stmt, "new can be applied only to reference types (got {0})", rr.EType);
} else {
// ---------- new C.Init(EE)
Contract.Assert(initCallName != null);
- var prevErrorCount = ErrorCount;
+ var prevErrorCount = reporter.Count(ErrorLevel.Error);
// We want to create a MemberSelectExpr for the initializing method. To do that, we create a throw-away receiver of the appropriate
// type, create an dot-suffix expression around this receiver, and then resolve it in the usual way for dot-suffix expressions.
var lhs = new ImplicitThisExpr(initCallTok) { Type = rr.EType };
var callLhs = new ExprDotName(initCallTok, lhs, initCallName, ret == null ? null : ret.LastComponent.OptTypeArguments);
- ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true, specContextOnly), true);
- if (prevErrorCount == ErrorCount) {
+ ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true), true);
+ if (prevErrorCount == reporter.Count(ErrorLevel.Error)) {
Contract.Assert(callLhs.ResolvedExpression is MemberSelectExpr); // since ResolveApplySuffix succeeded and call.Lhs denotes an expression (not a module or a type)
var methodSel = (MemberSelectExpr)callLhs.ResolvedExpression;
if (methodSel.Member is Method) {
rr.InitCall = new CallStmt(initCallTok, stmt.EndTok, new List<Expression>(), methodSel, rr.Arguments);
- ResolveCallStmt(rr.InitCall, specContextOnly, codeContext, rr.EType);
+ ResolveCallStmt(rr.InitCall, codeContext, rr.EType);
if (rr.InitCall.Method is Constructor) {
callsConstructor = true;
}
} else {
- Error(initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName);
+ reporter.Error(MessageSource.Resolver, initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName);
}
}
}
@@ -6113,10 +7284,10 @@ namespace Microsoft.Dafny
if (udt != null) {
var cl = (ClassDecl)udt.ResolvedClass; // cast is guaranteed by the call to rr.EType.IsRefType above, together with the "rr.EType is UserDefinedType" test
if (cl is TraitDecl) {
- Error(stmt, "new cannot be applied to a trait");
+ reporter.Error(MessageSource.Resolver, stmt, "new cannot be applied to a trait");
}
if (!callsConstructor && cl.HasConstructor) {
- Error(stmt, "when allocating an object of type '{0}', one of its constructor methods must be called", cl.Name);
+ reporter.Error(MessageSource.Resolver, stmt, "when allocating an object of type '{0}', one of its constructor methods must be called", cl.Name);
}
}
}
@@ -6126,12 +7297,14 @@ namespace Microsoft.Dafny
return rr.Type;
}
- MemberDecl ResolveMember(IToken tok, Type receiverType, string memberName, out NonProxyType nptype) {
+ MemberDecl ResolveMember(IToken tok, Type receiverType, string memberName, out NonProxyType nptype, bool classMembersOnly = false) {
Contract.Requires(tok != null);
Contract.Requires(receiverType != null);
Contract.Requires(memberName != null);
Contract.Ensures(Contract.Result<MemberDecl>() == null || Contract.ValueAtReturn(out nptype) != null);
+ PartiallySolveTypeConstraints(); // so that we can try to pick up the type of the receiver
+
nptype = null; // prepare for the worst
receiverType = receiverType.NormalizeExpand();
var opProxy = receiverType as OperationTypeProxy;
@@ -6145,7 +7318,7 @@ namespace Microsoft.Dafny
}
}
if (receiverType is TypeProxy) {
- Error(tok, "type of the receiver is not fully determined at this program point", receiverType);
+ reporter.Error(MessageSource.Resolver, tok, "type of the receiver is not fully determined at this program point", receiverType);
return null;
}
Contract.Assert(receiverType is NonProxyType); // there are only two kinds of types: proxies and non-proxies
@@ -6158,20 +7331,20 @@ namespace Microsoft.Dafny
if (!classMembers[cd].TryGetValue(memberName, out member)) {
var kind = cd is IteratorDecl ? "iterator" : "class";
if (memberName == "_ctor") {
- Error(tok, "{0} {1} does not have an anonymous constructor", kind, ctype.Name);
+ reporter.Error(MessageSource.Resolver, tok, "{0} {1} does not have an anonymous constructor", kind, ctype.Name);
} else {
// search the static members of the enclosing module or its imports
- if (moduleInfo.StaticMembers.TryGetValue(memberName, out member)) {
+ if (!classMembersOnly && moduleInfo.StaticMembers.TryGetValue(memberName, out member)) {
Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default
if (member is AmbiguousMemberDecl) {
var ambiguousMember = (AmbiguousMemberDecl)member;
- Error(tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", memberName, ambiguousMember.ModuleNames());
+ reporter.Error(MessageSource.Resolver, tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", memberName, ambiguousMember.ModuleNames());
} else {
nptype = GetReceiverType(tok, member);
return member;
}
} else {
- Error(tok, "member {0} does not exist in {2} {1}", memberName, ctype.Name, kind);
+ reporter.Error(MessageSource.Resolver, tok, "member {0} does not exist in {2} {1}", memberName, ctype.Name, kind);
}
}
return null;
@@ -6185,7 +7358,7 @@ namespace Microsoft.Dafny
if (dtd != null) {
MemberDecl member;
if (!datatypeMembers[dtd].TryGetValue(memberName, out member)) {
- Error(tok, "member {0} does not exist in datatype {1}", memberName, dtd.Name);
+ reporter.Error(MessageSource.Resolver, tok, "member {0} does not exist in datatype {1}", memberName, dtd.Name);
return null;
} else {
nptype = (UserDefinedType)receiverType;
@@ -6211,7 +7384,7 @@ namespace Microsoft.Dafny
}
}
- Error(tok, "type {0} does not have a member {1}", receiverType, memberName);
+ reporter.Error(MessageSource.Resolver, tok, "type {0} does not have a member {1}", receiverType, memberName);
return null;
}
@@ -6265,7 +7438,8 @@ namespace Microsoft.Dafny
if (arg == t.Arg) {
return type;
} else if (type is SetType) {
- return new SetType(arg);
+ var st = (SetType)type;
+ return new SetType(st.Finite, arg);
} else if (type is MultiSetType) {
return new MultiSetType(arg);
} else if (type is SeqType) {
@@ -6371,24 +7545,10 @@ namespace Microsoft.Dafny
{
public readonly ICodeContext codeContext;
public readonly bool twoState;
- public readonly bool DontCareAboutCompilation;
public ResolveOpts(ICodeContext codeContext, bool twoState) {
Contract.Requires(codeContext != null);
this.codeContext = codeContext;
this.twoState = twoState;
- DontCareAboutCompilation = codeContext.IsGhost;
- }
- public ResolveOpts(ICodeContext codeContext, bool twoState, bool dontCareAboutCompilation) {
- Contract.Requires(codeContext != null);
- this.codeContext = codeContext;
- this.twoState = twoState;
- this.DontCareAboutCompilation = dontCareAboutCompilation;
- }
- public ResolveOpts(ResolveOpts r, bool dontCareAboutCompilation) {
- Contract.Requires(r != null);
- this.codeContext = r.codeContext;
- this.twoState = r.twoState;
- this.DontCareAboutCompilation = dontCareAboutCompilation;
}
}
@@ -6434,10 +7594,10 @@ namespace Microsoft.Dafny
} else if (expr is NegationExpression) {
var e = (NegationExpression)expr;
- var errorCount = ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
ResolveExpression(e.E, opts);
e.Type = e.E.Type;
- if (errorCount != ErrorCount) {
+ if (errorCount != reporter.Count(ErrorLevel.Error)) {
// there were errors resolving the operand; take the quick way out and
// just let the (already erronous) subexpression be what the negation expression
// will resolve to
@@ -6471,9 +7631,9 @@ namespace Microsoft.Dafny
if (e.Value == null) {
e.Type = new ObjectTypeProxy();
} else if (e.Value is BigInteger) {
- e.Type = new OperationTypeProxy(true, false, false, false, false);
+ e.Type = new OperationTypeProxy(true, false, false, false, false, false);
} else if (e.Value is Basetypes.BigDec) {
- e.Type = new OperationTypeProxy(false, true, false, false, false);
+ e.Type = new OperationTypeProxy(false, true, false, false, false, false);
} else if (e.Value is bool) {
e.Type = Type.Bool;
} else if (e is CharLiteralExpr) {
@@ -6487,7 +7647,7 @@ namespace Microsoft.Dafny
}
} else if (expr is ThisExpr) {
if (!scope.AllowInstance) {
- Error(expr, "'this' is not allowed in a 'static' context");
+ reporter.Error(MessageSource.Resolver, expr, "'this' is not allowed in a 'static' context");
}
if (currentClass != null) {
expr.Type = GetThisType(expr.tok, currentClass); // do this regardless of scope.AllowInstance, for better error reporting
@@ -6499,19 +7659,19 @@ namespace Microsoft.Dafny
if (e.Var != null) {
expr.Type = e.Var.Type;
} else {
- Error(expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name);
+ reporter.Error(MessageSource.Resolver, expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name);
}
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
TopLevelDecl d;
if (!moduleInfo.TopLevels.TryGetValue(dtv.DatatypeName, out d)) {
- Error(expr.tok, "Undeclared datatype: {0}", dtv.DatatypeName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "Undeclared datatype: {0}", dtv.DatatypeName);
} else if (d is AmbiguousTopLevelDecl) {
var ad = (AmbiguousTopLevelDecl)d;
- Error(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", dtv.DatatypeName, ad.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", dtv.DatatypeName, ad.ModuleNames());
} else if (!(d is DatatypeDecl)) {
- Error(expr.tok, "Expected datatype: {0}", dtv.DatatypeName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "Expected datatype: {0}", dtv.DatatypeName);
} else {
ResolveDatatypeValue(opts, dtv, (DatatypeDecl)d);
}
@@ -6522,12 +7682,11 @@ namespace Microsoft.Dafny
foreach (Expression ee in e.Elements) {
ResolveExpression(ee, opts);
Contract.Assert(ee.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(elementType, ee.Type)) {
- Error(ee, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", ee.Type, elementType);
- }
+ ConstrainTypes(elementType, ee.Type, ee, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", ee.Type, elementType);
}
if (expr is SetDisplayExpr) {
- expr.Type = new SetType(elementType);
+ var se = (SetDisplayExpr)expr;
+ expr.Type = new SetType(se.Finite, elementType);
} else if (expr is MultiSetDisplayExpr) {
expr.Type = new MultiSetType(elementType);
} else {
@@ -6540,32 +7699,28 @@ namespace Microsoft.Dafny
foreach (ExpressionPair p in e.Elements) {
ResolveExpression(p.A, opts);
Contract.Assert(p.A.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(domainType, p.A.Type)) {
- Error(p.A, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.A.Type, domainType);
- }
+ ConstrainTypes(domainType, p.A.Type, p.A, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.A.Type, domainType);
ResolveExpression(p.B, opts);
Contract.Assert(p.B.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(rangeType, p.B.Type)) {
- Error(p.B, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.B.Type, rangeType);
- }
+ ConstrainTypes(rangeType, p.B.Type, p.B, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.B.Type, rangeType);
}
expr.Type = new MapType(e.Finite, domainType, rangeType);
} else if (expr is NameSegment) {
var e = (NameSegment)expr;
ResolveNameSegment(e, true, null, opts, false);
if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) {
- Error(e.tok, "name of module ({0}) is used as a variable", e.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a variable", e.Name);
} else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) {
- Error(e.tok, "name of type ({0}) is used as a variable", e.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a variable", e.Name);
}
} else if (expr is ExprDotName) {
var e = (ExprDotName)expr;
ResolveDotSuffix(e, true, null, opts, false);
if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) {
- Error(e.tok, "name of module ({0}) is used as a variable", e.SuffixName);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a variable", e.SuffixName);
} else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) {
- Error(e.tok, "name of type ({0}) is used as a variable", e.SuffixName);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a variable", e.SuffixName);
}
} else if (expr is ApplySuffix) {
@@ -6605,7 +7760,7 @@ namespace Microsoft.Dafny
var field = (Field)member;
e.Member = field;
if (e.Obj is StaticReceiverExpr) {
- Error(expr, "a field must be selected via an object, not just a class name");
+ reporter.Error(MessageSource.Resolver, expr, "a field must be selected via an object, not just a class name");
}
var ctype = nptype as UserDefinedType;
if (ctype == null) {
@@ -6617,7 +7772,7 @@ namespace Microsoft.Dafny
e.Type = SubstType(field.Type, subst);
}
} else {
- Error(expr, "member {0} in type {1} does not refer to a field or a function", e.MemberName, nptype);
+ reporter.Error(MessageSource.Resolver, expr, "member {0} in type {1} does not refer to a field or a function", e.MemberName, nptype);
}
} else if (expr is SeqSelectExpr) {
@@ -6630,17 +7785,13 @@ namespace Microsoft.Dafny
ResolveExpression(e.Array, opts);
Contract.Assert(e.Array.Type != null); // follows from postcondition of ResolveExpression
Type elementType = new InferredTypeProxy();
- if (!UnifyTypes(e.Array.Type, ResolvedArrayType(e.Array.tok, e.Indices.Count, elementType, opts.codeContext))) {
- Error(e.Array, "array selection requires an array{0} (got {1})", e.Indices.Count, e.Array.Type);
- }
+ ConstrainTypes(e.Array.Type, ResolvedArrayType(e.Array.tok, e.Indices.Count, elementType, opts.codeContext), e.Array, "array selection requires an array{0} (got {1})", e.Indices.Count, e.Array.Type);
int i = 0;
foreach (Expression idx in e.Indices) {
Contract.Assert(idx != null);
ResolveExpression(idx, opts);
Contract.Assert(idx.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(idx.Type, new OperationTypeProxy(true, false, false, false, false))) {
- Error(idx, "array selection requires integer-based numeric indices (got {0} for index {1})", idx.Type, i);
- }
+ ConstrainTypes(idx.Type, new OperationTypeProxy(true, false, false, false, false, false), idx, "array selection requires integer-based numeric indices (got {0} for index {1})", idx.Type, i);
i++;
}
e.Type = elementType;
@@ -6655,131 +7806,71 @@ namespace Microsoft.Dafny
if (UnifyTypes(e.Seq.Type, new SeqType(elementType))) {
ResolveExpression(e.Index, opts);
Contract.Assert(e.Index.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Index.Type, Type.Int)) {
- Error(e.Index, "sequence update requires integer index (got {0})", e.Index.Type);
- }
+ ConstrainTypes(e.Index.Type, Type.Int, e.Index, "sequence update requires integer index (got {0})", e.Index.Type);
ResolveExpression(e.Value, opts);
Contract.Assert(e.Value.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Value.Type, elementType)) {
- Error(e.Value, "sequence update requires the value to have the element type of the sequence (got {0})", e.Value.Type);
- }
+ ConstrainTypes(e.Value.Type, elementType, e.Value, "sequence update requires the value to have the element type of the sequence (got {0})", e.Value.Type);
expr.Type = e.Seq.Type;
} else if (UnifyTypes(e.Seq.Type, new MapType(true, domainType, rangeType))) {
ResolveExpression(e.Index, opts);
- if (!UnifyTypes(e.Index.Type, domainType)) {
- Error(e.Index, "map update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type);
- }
+ ConstrainTypes(e.Index.Type, domainType, e.Index, "map update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type);
ResolveExpression(e.Value, opts);
- if (!UnifyTypes(e.Value.Type, rangeType)) {
- Error(e.Value, "map update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type);
- }
+ ConstrainTypes(e.Value.Type, rangeType, e.Value, "map update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type);
expr.Type = e.Seq.Type;
} else if (UnifyTypes(e.Seq.Type, new MapType(false, domainType, rangeType))) {
ResolveExpression(e.Index, opts);
- if (!UnifyTypes(e.Index.Type, domainType)) {
- Error(e.Index, "imap update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type);
- }
+ ConstrainTypes(e.Index.Type, domainType, e.Index, "imap update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type);
ResolveExpression(e.Value, opts);
- if (!UnifyTypes(e.Value.Type, rangeType)) {
- Error(e.Value, "imap update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type);
- }
+ ConstrainTypes(e.Value.Type, rangeType, e.Value, "imap update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type);
expr.Type = e.Seq.Type;
} else if (UnifyTypes(e.Seq.Type, new MultiSetType(elementType))) {
ResolveExpression(e.Index, opts);
- if (!UnifyTypes(e.Index.Type, elementType)) {
- Error(e.Index, "multiset update requires domain element to be of type {0} (got {1})", elementType, e.Index.Type);
- }
+ ConstrainTypes(e.Index.Type, elementType, e.Index, "multiset update requires domain element to be of type {0} (got {1})", elementType, e.Index.Type);
ResolveExpression(e.Value, opts);
- if (!UnifyTypes(e.Value.Type, new OperationTypeProxy(true, false, false, false, false))) {
- Error(e.Value, "multiset update requires integer-based numeric value (got {0})", e.Value.Type);
- }
+ ConstrainTypes(e.Value.Type, new OperationTypeProxy(true, false, false, false, false, false), e.Value, "multiset update requires integer-based numeric value (got {0})", e.Value.Type);
expr.Type = e.Seq.Type;
} else if (e.Seq.Type.IsDatatype) {
- var dt = e.Seq.Type.AsDatatype;
- DatatypeCtor ctor = null;
-
- // Let en = e and e(n-1) = en.Seq
- // We're currently looking at e = e(n-1)[en.Index := en.Value]
- // Let e(n-2) = e(n-1).Seq, e(n-3) = e(n-2).Seq, etc.
- // Let's extract e = e0[e1.Index := e1.Value]...[en.Index := en.Value]
- var IndexToValue = new Dictionary<string,Tuple<DatatypeDestructor,Expression>>();
+ // combine a nest of datatype updates into one single DatatypeUpdate expression
+ var memberUpdates = new List<Tuple<IToken, string, Expression>>();
Expression eIter = e;
while (eIter is SeqUpdateExpr) {
var ei = (SeqUpdateExpr)eIter;
-
- if (!(ei.Index is NameSegment|| (ei.Index is LiteralExpr && ((LiteralExpr)ei.Index).Value is BigInteger))) {
- Error(expr, "datatype updates must be to datatype destructors");
+ if (ei.Index is NameSegment) {
+ var seg = (NameSegment)ei.Index;
+ memberUpdates.Add(new Tuple<IToken,string,Expression>(ei.Index.tok, seg.Name, ei.Value));
+ } else if (ei.Index is LiteralExpr && ((LiteralExpr)ei.Index).Value is BigInteger) {
+ var lit = (LiteralExpr)ei.Index;
+ var nm = lit.tok.val; // note, take the string of digits, not the parsed integer
+ memberUpdates.Add(new Tuple<IToken,string,Expression>(ei.Index.tok, nm, ei.Value));
} else {
- string destructor_str = null;
-
- if (ei.Index is NameSegment) {
- var seg = (NameSegment)ei.Index;
- destructor_str = seg.Name;
- } else {
- Contract.Assert(ei.Index is LiteralExpr && ((LiteralExpr)ei.Index).Value is BigInteger);
- destructor_str = ((LiteralExpr)ei.Index).tok.val; // note, take the string of digits, not the parsed integer
- }
-
- Contract.Assert(destructor_str != null);
- if (IndexToValue.ContainsKey(destructor_str)) {
- // Don't bother trying to optimize this case; we'd have to drop one of the updates,
- // which makes resolving the dropped update an annoyance.
- Warning(ei.tok, "update to {0} overwritten by another update to {1}", destructor_str, destructor_str);
- break;
- }
- MemberDecl member;
- if (!datatypeMembers[dt].TryGetValue(destructor_str, out member)) {
- Error(expr, "member {0} does not exist in datatype {1}", destructor_str, dt.Name);
- } else {
- DatatypeDestructor destructor = (DatatypeDestructor)member;
- if (ctor != null && ctor != destructor.EnclosingCtor) {
- // Don't bother optimizing case where destructors come from different constructors
- break;
- }
- IndexToValue.Add(destructor_str, Tuple.Create(destructor, ei.Value));
- ctor = destructor.EnclosingCtor;
- }
+ reporter.Error(MessageSource.Resolver, expr, "datatype updates must be to datatype destructors");
}
eIter = ei.Seq;
}
- var e0 = eIter;
-
- // Rewrite an update of the form "dt[dtor := E]" to be "let d' := dt in dtCtr(E, d'.dtor2, d'.dtor3,...)"
- // Wrapping it in a let expr avoids exponential growth in the size of the expression
- // More generally, rewrite "E0[dtor1 := E1][dtor2 := E2]...[dtorn := En]" to
- // "let d' := E0 in dtCtr(...mixtures of Ek and d'.dtorj...)"
-
- // Create a unique name for d', the variable we introduce in the let expression
- string tmpName = FreshTempVarName("dt_update_tmp#", opts.codeContext);
- IdentifierExpr tmpVarIdExpr = new IdentifierExpr(e0.tok, tmpName);
- BoundVar tmpVarBv = new BoundVar(e0.tok, tmpName, e0.Type);
-
- // Build the arguments to the datatype constructor, using the updated value in the appropriate slot
- List<Expression> ctor_args = new List<Expression>();
- foreach (Formal d in ctor.Formals) {
- Expression v = null;
- foreach (var dvPair in IndexToValue.Values) {
- var destructor = dvPair.Item1;
- if (d == destructor.CorrespondingFormal) {
- Contract.Assert(v == null);
- v = dvPair.Item2;
- }
- }
- ctor_args.Add(v ?? new ExprDotName(expr.tok, tmpVarIdExpr, d.Name, null));
+ var let = ResolveDatatypeUpdate(expr.tok, eIter, e.Seq.Type.AsDatatype, memberUpdates, true, opts);
+ if (let != null) {
+ reporter.Warning(MessageSource.Resolver, expr.tok, "datatype update syntax D[f := E] is deprecated; the new syntax is D.(f := E)");
+ e.ResolvedUpdateExpr = let;
+ expr.Type = e.Seq.Type;
}
- DatatypeValue ctor_call = new DatatypeValue(expr.tok, ctor.EnclosingDatatype.Name, ctor.Name, ctor_args);
-
- CasePattern tmpVarPat = new CasePattern(e0.tok, tmpVarBv);
- LetExpr let = new LetExpr(e0.tok, new List<CasePattern>() { tmpVarPat }, new List<Expression>() { e0 }, ctor_call, true);
-
- ResolveExpression(let, opts);
- e.ResolvedUpdateExpr = let;
+ } else {
+ reporter.Error(MessageSource.Resolver, expr, "update requires a sequence, map, multiset, or datatype (got {0})", e.Seq.Type);
+ }
- expr.Type = e0.Type;
+ } else if (expr is DatatypeUpdateExpr) {
+ var e = (DatatypeUpdateExpr)expr;
+ ResolveExpression(e.Root, opts);
+ var ty = e.Root.Type;
+ if (!ty.IsDatatype) {
+ reporter.Error(MessageSource.Resolver, expr, "datatype update expression requires a root expression of a datatype (got {0})", ty);
} else {
- Error(expr, "update requires a sequence, map, or datatype (got {0})", e.Seq.Type);
+ var let = ResolveDatatypeUpdate(expr.tok, e.Root, ty.AsDatatype, e.Updates, false, opts);
+ if (let != null) {
+ e.ResolvedExpression = let;
+ expr.Type = ty;
+ }
}
} else if (expr is FunctionCallExpr) {
@@ -6794,14 +7885,12 @@ namespace Microsoft.Dafny
}
var fnType = e.Function.Type.AsArrowType;
if (fnType == null) {
- Error(e.tok, "non-function expression (of type {0}) is called with parameters", e.Function.Type);
+ reporter.Error(MessageSource.Resolver, e.tok, "non-function expression (of type {0}) is called with parameters", e.Function.Type);
} else if (fnType.Arity != e.Args.Count) {
- Error(e.tok, "wrong number of arguments to function application (function type '{0}' expects {1}, got {2})", fnType, fnType.Arity, e.Args.Count);
+ reporter.Error(MessageSource.Resolver, e.tok, "wrong number of arguments to function application (function type '{0}' expects {1}, got {2})", fnType, fnType.Arity, e.Args.Count);
} else {
for (var i = 0; i < fnType.Arity; i++) {
- if (!UnifyTypes(fnType.Args[i], e.Args[i].Type)) {
- Error(e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type);
- }
+ ConstrainTypes(fnType.Args[i], e.Args[i].Type, e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type);
}
}
expr.Type = fnType == null ? new InferredTypeProxy() : fnType.Result;
@@ -6809,7 +7898,7 @@ namespace Microsoft.Dafny
} else if (expr is OldExpr) {
OldExpr e = (OldExpr)expr;
if (!opts.twoState) {
- Error(expr, "old expressions are not allowed in this context");
+ reporter.Error(MessageSource.Resolver, expr, "old expressions are not allowed in this context");
}
ResolveExpression(e.E, opts);
expr.Type = e.E.Type;
@@ -6817,8 +7906,8 @@ namespace Microsoft.Dafny
} else if (expr is MultiSetFormingExpr) {
MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
ResolveExpression(e.E, opts);
- if (!UnifyTypes(e.E.Type, new SetType(new InferredTypeProxy())) && !UnifyTypes(e.E.Type, new SeqType(new InferredTypeProxy()))) {
- Error(e.tok, "can only form a multiset from a seq or set.");
+ if (!UnifyTypes(e.E.Type, new SetType(true, new InferredTypeProxy())) && !UnifyTypes(e.E.Type, new SeqType(new InferredTypeProxy()))) {
+ reporter.Error(MessageSource.Resolver, e.tok, "can only form a multiset from a seq or set.");
}
expr.Type = new MultiSetType(e.E.Type.AsCollectionType.Arg);
@@ -6828,20 +7917,16 @@ namespace Microsoft.Dafny
Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression
switch (e.Op) {
case UnaryOpExpr.Opcode.Not:
- if (!UnifyTypes(e.E.Type, Type.Bool)) {
- Error(expr, "logical negation expects a boolean argument (instead got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, Type.Bool, expr, "logical negation expects a boolean argument (instead got {0})", e.E.Type);
expr.Type = Type.Bool;
break;
case UnaryOpExpr.Opcode.Cardinality:
- if (!UnifyTypes(e.E.Type, new CollectionTypeProxy(new InferredTypeProxy(), false))) {
- Error(expr, "size operator expects a collection argument (instead got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, new CollectionTypeProxy(new InferredTypeProxy(), false, false), expr, "size operator expects a collection argument (instead got {0})", e.E.Type);
expr.Type = Type.Int;
break;
case UnaryOpExpr.Opcode.Fresh:
if (!opts.twoState) {
- Error(expr, "fresh expressions are not allowed in this context");
+ reporter.Error(MessageSource.Resolver, expr, "fresh expressions are not allowed in this context");
}
// the type of e.E must be either an object or a collection of objects
Type t = e.E.Type.NormalizeExpand();
@@ -6856,7 +7941,7 @@ namespace Microsoft.Dafny
} else if (t.IsDatatype) {
// fine, treat this as the datatype itself.
} else {
- Error(expr, "the argument of a fresh expression must denote an object or a collection of objects (instead got {0})", e.E.Type);
+ reporter.Error(MessageSource.Resolver, expr, "the argument of a fresh expression must denote an object or a collection of objects (instead got {0})", e.E.Type);
}
expr.Type = Type.Bool;
break;
@@ -6869,15 +7954,11 @@ namespace Microsoft.Dafny
ResolveType(e.tok, e.ToType, opts.codeContext, new ResolveTypeOption(ResolveTypeOptionEnum.DontInfer), null);
ResolveExpression(e.E, opts);
if (e.ToType.IsNumericBased(Type.NumericPersuation.Int)) {
- if (!UnifyTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false))) {
- Error(expr, "type conversion to an int-based type is allowed only from numeric types (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false, false), expr, "type conversion to an int-based type is allowed only from numeric types (got {0})", e.E.Type);
} else if (e.ToType.IsNumericBased(Type.NumericPersuation.Real)) {
- if (!UnifyTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false))) {
- Error(expr, "type conversion to a real-based type is allowed only from numeric types (got {0})", e.E.Type);
- }
+ ConstrainTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false, false), expr, "type conversion to a real-based type is allowed only from numeric types (got {0})", e.E.Type);
} else {
- Error(expr, "type conversions are not supported to this type (got {0})", e.ToType);
+ reporter.Error(MessageSource.Resolver, expr, "type conversions are not supported to this type (got {0})", e.ToType);
}
e.Type = e.ToType;
@@ -6893,12 +7974,8 @@ namespace Microsoft.Dafny
case BinaryExpr.Opcode.Exp:
case BinaryExpr.Opcode.And:
case BinaryExpr.Opcode.Or:
- if (!UnifyTypes(e.E0.Type, Type.Bool)) {
- Error(expr, "first argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
- }
- if (!UnifyTypes(e.E1.Type, Type.Bool)) {
- Error(expr, "second argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type);
- }
+ ConstrainTypes(e.E0.Type, Type.Bool, expr, "first argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
+ ConstrainTypes(e.E1.Type, Type.Bool, expr, "second argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type);
expr.Type = Type.Bool;
break;
@@ -6918,20 +7995,18 @@ namespace Microsoft.Dafny
// unification will succeed.
} else {
// The types are not comparable and do not unify. It's time for an error message.
- Error(expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type);
+ reporter.Error(MessageSource.Resolver, expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type);
}
expr.Type = Type.Bool;
break;
case BinaryExpr.Opcode.Disjoint:
// TODO: the error messages are backwards from what (ideally) they should be. this is necessary because UnifyTypes can't backtrack.
- if (!UnifyTypes(e.E0.Type, e.E1.Type)) {
- Error(expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type);
- }
- if (!UnifyTypes(e.E0.Type, new SetType(new InferredTypeProxy())) &&
+ ConstrainTypes(e.E0.Type, e.E1.Type, expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type);
+ if (!UnifyTypes(e.E0.Type, new SetType(true, new InferredTypeProxy())) &&
!UnifyTypes(e.E0.Type, new MultiSetType(new InferredTypeProxy())) &&
!UnifyTypes(e.E0.Type, new MapType(true, new InferredTypeProxy(), new InferredTypeProxy()))) {
- Error(expr, "arguments must be of a [multi]set or map type (got {0})", e.E0.Type);
+ reporter.Error(MessageSource.Resolver, expr, "arguments must be of a [multi]set or map type (got {0})", e.E0.Type);
}
expr.Type = Type.Bool;
break;
@@ -6940,34 +8015,25 @@ namespace Microsoft.Dafny
case BinaryExpr.Opcode.Le:
case BinaryExpr.Opcode.Add: {
if (e.Op == BinaryExpr.Opcode.Lt && (e.E0.Type.NormalizeExpand().IsIndDatatype || e.E0.Type.IsTypeParameter)) {
- if (UnifyTypes(e.E1.Type, new DatatypeProxy(false, false))) {
+ if (ConstrainTypes(e.E1.Type, new DatatypeProxy(false, false), expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type)) {
e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankLt;
- } else {
- Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type);
}
expr.Type = Type.Bool;
} else if (e.Op == BinaryExpr.Opcode.Lt && e.E1.Type.NormalizeExpand().IsIndDatatype) {
- if (UnifyTypes(e.E0.Type, new DatatypeProxy(false, true))) {
+ if (ConstrainTypes(e.E0.Type, new DatatypeProxy(false, true), expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type)) {
e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankLt;
- } else {
- Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type);
}
expr.Type = Type.Bool;
} else {
- bool err = false;
bool isComparison = e.Op != BinaryExpr.Opcode.Add;
- if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, true, true))) {
- Error(expr, "arguments to {0} must be of a numeric type{2} or a collection type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type,
- isComparison ? ", char," : "");
- err = true;
- }
- if (!UnifyTypes(e.E1.Type, e.E0.Type)) {
- Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
- err = true;
- }
+ var good0 = ConstrainTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, true, true, true),
+ expr, "arguments to {0} must be of a numeric type{2} or a collection type (instead got {1})",
+ BinaryExpr.OpcodeString(e.Op), e.E0.Type, isComparison ? ", char," : "");
+ var good1 = ConstrainTypes(e.E1.Type, e.E0.Type,
+ expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
if (isComparison) {
expr.Type = Type.Bool;
- } else if (!err) {
+ } else if (good0 && good1) {
expr.Type = e.E0.Type;
}
}
@@ -6979,34 +8045,24 @@ namespace Microsoft.Dafny
case BinaryExpr.Opcode.Gt:
case BinaryExpr.Opcode.Ge: {
if (e.Op == BinaryExpr.Opcode.Gt && e.E0.Type.NormalizeExpand().IsIndDatatype) {
- if (UnifyTypes(e.E1.Type, new DatatypeProxy(false, true))) {
+ if (ConstrainTypes(e.E1.Type, new DatatypeProxy(false, true), expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type)) {
e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankGt;
- } else {
- Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type);
}
expr.Type = Type.Bool;
} else if (e.Op == BinaryExpr.Opcode.Gt && (e.E1.Type.NormalizeExpand().IsIndDatatype || e.E1.Type.IsTypeParameter)) {
- if (UnifyTypes(e.E0.Type, new DatatypeProxy(false, false))) {
+ if (ConstrainTypes(e.E0.Type, new DatatypeProxy(false, false), expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type)) {
e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankGt;
- } else {
- Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type);
}
expr.Type = Type.Bool;
} else {
- bool err = false;
bool isComparison = e.Op == BinaryExpr.Opcode.Gt || e.Op == BinaryExpr.Opcode.Ge;
- if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, false, true))) {
- Error(expr, "arguments to {0} must be of a numeric type{2} or a set type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type,
- isComparison ? ", char, " : "");
- err = true;
- }
- if (!UnifyTypes(e.E1.Type, e.E0.Type)) {
- Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
- err = true;
- }
+ var good0 = ConstrainTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, false, true, true),
+ expr, "arguments to {0} must be of a numeric type{2} or a set type (instead got {1})",
+ BinaryExpr.OpcodeString(e.Op), e.E0.Type, isComparison ? ", char, " : "");
+ var good1 = ConstrainTypes(e.E1.Type, e.E0.Type, expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
if (isComparison) {
expr.Type = Type.Bool;
- } else if (!err) {
+ } else if (good0 && good1) {
expr.Type = e.E0.Type;
}
}
@@ -7015,29 +8071,23 @@ namespace Microsoft.Dafny
case BinaryExpr.Opcode.In:
case BinaryExpr.Opcode.NotIn:
- if (!UnifyTypes(e.E1.Type, new CollectionTypeProxy(e.E0.Type, true))) {
- Error(expr, "second argument to \"{0}\" must be a set, multiset, or sequence with elements of type {1}, or a map with domain {1} (instead got {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
- }
+ ConstrainTypes(e.E1.Type, new CollectionTypeProxy(e.E0.Type, true, true), expr, "second argument to \"{0}\" must be a set, multiset, or sequence with elements of type {1}, or a map with domain {1} (instead got {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
expr.Type = Type.Bool;
break;
case BinaryExpr.Opcode.Div:
- if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, false, false, false))) {
- Error(expr, "first argument to {0} must be of numeric type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
- }
- if (!UnifyTypes(e.E1.Type, e.E0.Type)) {
- Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
- }
+ ConstrainTypes(e.E0.Type, new OperationTypeProxy(true, true, false, false, false, false),
+ expr, "first argument to {0} must be of numeric type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
+ ConstrainTypes(e.E1.Type, e.E0.Type,
+ expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type);
expr.Type = e.E0.Type;
break;
case BinaryExpr.Opcode.Mod:
- if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, false, false, false, false))) {
- Error(expr, "first argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
- }
- if (!UnifyTypes(e.E1.Type, e.E0.Type)) {
- Error(expr, "second argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type);
- }
+ ConstrainTypes(e.E0.Type, new OperationTypeProxy(true, false, false, false, false, false),
+ expr, "first argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type);
+ ConstrainTypes(e.E1.Type, e.E0.Type,
+ expr, "second argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type);
expr.Type = e.E0.Type;
break;
@@ -7055,15 +8105,12 @@ namespace Microsoft.Dafny
switch (e.Op) {
case TernaryExpr.Opcode.PrefixEqOp:
case TernaryExpr.Opcode.PrefixNeqOp:
- if (!UnifyTypes(e.E0.Type, Type.Int)) {
- Error(e.E0, "prefix-equality limit argument must be an integer expression (got {0})", e.E0.Type);
- }
- if (!UnifyTypes(e.E1.Type, new DatatypeProxy(true))) {
- Error(expr, "arguments to prefix equality must be codatatypes (instead of {0})", e.E1.Type);
- }
- if (!UnifyTypes(e.E1.Type, e.E2.Type)) {
- Error(expr, "arguments must have the same type (got {0} and {1})", e.E1.Type, e.E2.Type);
- }
+ ConstrainTypes(e.E0.Type, Type.Int,
+ e.E0, "prefix-equality limit argument must be an integer expression (got {0})", e.E0.Type);
+ ConstrainTypes(e.E1.Type, new DatatypeProxy(true),
+ expr, "arguments to prefix equality must be codatatypes (instead of {0})", e.E1.Type);
+ ConstrainTypes(e.E1.Type, e.E2.Type,
+ expr, "arguments must have the same type (got {0} and {1})", e.E1.Type, e.E2.Type);
expr.Type = Type.Bool;
break;
default:
@@ -7079,7 +8126,7 @@ namespace Microsoft.Dafny
}
scope.PushMarker();
if (e.LHSs.Count != e.RHSs.Count) {
- Error(expr, "let expression must have same number of LHSs (found {0}) as RHSs (found {1})", e.LHSs.Count, e.RHSs.Count);
+ reporter.Error(MessageSource.Resolver, expr, "let expression must have same number of LHSs (found {0}) as RHSs (found {1})", e.LHSs.Count, e.RHSs.Count);
}
var i = 0;
foreach (var lhs in e.LHSs) {
@@ -7088,199 +8135,131 @@ namespace Microsoft.Dafny
// Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors
var c = 0;
foreach (var v in lhs.Vars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate let-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "let-variable");
c++;
}
if (c == 0) {
// Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal
- Error(lhs.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable");
+ reporter.Error(MessageSource.Resolver, lhs.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable");
}
i++;
}
} else {
// let-such-that expression
if (e.RHSs.Count != 1) {
- Error(expr, "let-such-that expression must have just one RHS (found {0})", e.RHSs.Count);
+ reporter.Error(MessageSource.Resolver, expr, "let-such-that expression must have just one RHS (found {0})", e.RHSs.Count);
}
// the bound variables are in scope in the RHS of a let-such-that expression
scope.PushMarker();
foreach (var lhs in e.LHSs) {
Contract.Assert(lhs.Var != null); // the parser already checked that every LHS is a BoundVar, not a general pattern
var v = lhs.Var;
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate let-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "let-variable");
ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
}
foreach (var rhs in e.RHSs) {
ResolveExpression(rhs, opts);
- if (!UnifyTypes(rhs.Type, Type.Bool)) {
- Error(rhs.tok, "type of RHS of let-such-that expression must be boolean (got {0})", rhs.Type);
- }
- }
- if (!opts.DontCareAboutCompilation && !e.BoundVars.All(bv => bv.IsGhost)) {
- needFiniteBoundsChecks_LetSuchThatExpr.Add(e);
+ ConstrainTypes(rhs.Type, Type.Bool, rhs.tok, "type of RHS of let-such-that expression must be boolean (got {0})", rhs.Type);
}
}
ResolveExpression(e.Body, opts);
- ResolveAttributes(e.Attributes, new ResolveOpts(opts, true));
+ ResolveAttributes(e.Attributes, opts);
scope.PopMarker();
expr.Type = e.Body.Type;
-
} else if (expr is NamedExpr) {
var e = (NamedExpr)expr;
ResolveExpression(e.Body, opts);
if (e.Contract != null) ResolveExpression(e.Contract, opts);
e.Type = e.Body.Type;
} else if (expr is QuantifierExpr) {
- QuantifierExpr e = (QuantifierExpr)expr;
- int prevErrorCount = ErrorCount;
+ var e = (QuantifierExpr)expr;
+ opts.codeContext.ContainsQuantifier = true;
+ Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
bool _val = true;
bool typeQuantifier = Attributes.ContainsBool(e.Attributes, "typeQuantifier", ref _val) && _val;
allTypeParameters.PushMarker();
ResolveTypeParameters(e.TypeArgs, true, e);
scope.PushMarker();
foreach (BoundVar v in e.BoundVars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate bound-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "bound-variable");
var option = typeQuantifier ? new ResolveTypeOption(e) : new ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies);
ResolveType(v.tok, v.Type, opts.codeContext, option, typeQuantifier ? e.TypeArgs : null);
}
if (e.TypeArgs.Count > 0 && !typeQuantifier) {
- Error(expr, "a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier");
+ reporter.Error(MessageSource.Resolver, expr, "a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier");
}
if (e.Range != null) {
- ResolveExpression(e.Range, new ResolveOpts(opts, true));
+ ResolveExpression(e.Range, opts);
Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Range.Type, Type.Bool)) {
- Error(expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type);
- }
+ ConstrainTypes(e.Range.Type, Type.Bool, expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type);
}
- ResolveExpression(e.Term, new ResolveOpts(opts, true));
+ ResolveExpression(e.Term, opts);
Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Term.Type, Type.Bool)) {
- Error(expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type);
- }
+ ConstrainTypes(e.Term.Type, Type.Bool, expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type);
// Since the body is more likely to infer the types of the bound variables, resolve it
// first (above) and only then resolve the attributes (below).
- ResolveAttributes(e.Attributes, new ResolveOpts(opts, true));
+ ResolveAttributes(e.Attributes, opts);
scope.PopMarker();
allTypeParameters.PopMarker();
expr.Type = Type.Bool;
- if (prevErrorCount == ErrorCount) {
- var missingBounds = new List<BoundVar>();
- CheckTypeInference(e.LogicalBody()); // we need to resolve operators before the call to DiscoverBounds
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, false, missingBounds);
- if (missingBounds.Count != 0) {
- // Report errors here about quantifications that depend on the allocation state.
- var mb = missingBounds;
- if (opts.codeContext is Function) {
- mb = new List<BoundVar>(); // (who cares if we allocate another array; this happens only in the case of a resolution error anyhow)
- foreach (var bv in missingBounds) {
- if (bv.Type.IsRefType) {
- Error(expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name);
- } else {
- mb.Add(bv);
- }
- }
- }
- if (mb.Count != 0) {
- e.MissingBounds = mb;
- }
- }
- }
-
} else if (expr is SetComprehension) {
var e = (SetComprehension)expr;
- int prevErrorCount = ErrorCount;
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
scope.PushMarker();
foreach (BoundVar v in e.BoundVars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate bound-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "bound-variable");
ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
}
ResolveExpression(e.Range, opts);
Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Range.Type, Type.Bool)) {
- Error(expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type);
- }
+ ConstrainTypes(e.Range.Type, Type.Bool, expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type);
ResolveExpression(e.Term, opts);
Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression
- ResolveAttributes(e.Attributes, new ResolveOpts(opts, true));
+ ResolveAttributes(e.Attributes, opts);
scope.PopMarker();
- expr.Type = new SetType(e.Term.Type);
-
- if (opts.DontCareAboutCompilation && (e.Term.Type.IsRefType || e.Term.Type.IsBoolType) || e.Term.Type.IsCharType) {
- // ok, term type is finite and we're in a ghost context
- } else {
- needFiniteBoundsChecks_SetComprehension.Add(e);
- }
+ expr.Type = new SetType(e.Finite, e.Term.Type);
} else if (expr is MapComprehension) {
var e = (MapComprehension)expr;
- int prevErrorCount = ErrorCount;
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
scope.PushMarker();
if (e.BoundVars.Count != 1) {
- Error(e.tok, "a map comprehension must have exactly one bound variable.");
+ reporter.Error(MessageSource.Resolver, e.tok, "a map comprehension must have exactly one bound variable.");
}
foreach (BoundVar v in e.BoundVars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate bound-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "bound-variable");
ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
}
ResolveExpression(e.Range, opts);
Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Range.Type, Type.Bool)) {
- Error(expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type);
- }
+ ConstrainTypes(e.Range.Type, Type.Bool, expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type);
ResolveExpression(e.Term, opts);
Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression
- ResolveAttributes(e.Attributes, new ResolveOpts(opts, true));
+ ResolveAttributes(e.Attributes, opts);
scope.PopMarker();
expr.Type = new MapType(e.Finite, e.BoundVars[0].Type, e.Term.Type);
- if (prevErrorCount == ErrorCount) {
- var missingBounds = new List<BoundVar>();
- CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds);
- if (missingBounds.Count != 0) {
- e.MissingBounds = missingBounds;
- if (e.Finite) {
- foreach (var bv in e.MissingBounds) {
- Error(expr, "a map comprehension must produce a finite domain, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
- }
- }
- }
- }
} else if (expr is LambdaExpr) {
var e = (LambdaExpr)expr;
- int prevErrorCount = ErrorCount;
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
scope.PushMarker();
foreach (BoundVar v in e.BoundVars) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate bound-variable name: {0}", v.Name);
- }
+ ScopePushAndReport(scope, v, "bound-variable");
ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
}
if (e.Range != null) {
ResolveExpression(e.Range, opts);
Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Range.Type, Type.Bool)) {
- Error(expr, "Precondition must be boolean (got {0})", e.Range.Type);
- }
+ ConstrainTypes(e.Range.Type, Type.Bool, expr, "Precondition must be boolean (got {0})", e.Range.Type);
}
foreach (var read in e.Reads) {
- ResolveFrameExpression(read, true, false, opts.codeContext);
+ ResolveFrameExpression(read, true, opts.codeContext);
}
ResolveExpression(e.Term, opts);
@@ -7288,17 +8267,17 @@ namespace Microsoft.Dafny
scope.PopMarker();
expr.Type = new ArrowType(e.tok, Util.Map(e.BoundVars, v => v.Type), e.Body.Type, builtIns.SystemModule);
} else if (expr is WildcardExpr) {
- expr.Type = new SetType(new ObjectType());
+ expr.Type = new SetType(true, new ObjectType());
} else if (expr is StmtExpr) {
var e = (StmtExpr)expr;
- int prevErrorCount = ErrorCount;
- ResolveStatement(e.S, true, opts.codeContext);
- if (ErrorCount == prevErrorCount) {
+ int prevErrorCount = reporter.Count(ErrorLevel.Error);
+ ResolveStatement(e.S, opts.codeContext);
+ if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {
var r = e.S as UpdateStmt;
if (r != null && r.ResolvedStatements.Count == 1) {
var call = r.ResolvedStatements[0] as CallStmt;
if (call.Method.Mod.Expressions.Count != 0) {
- Error(call, "calls to methods with side-effects are not allowed inside a statement expression");
+ reporter.Error(MessageSource.Resolver, call, "calls to methods with side-effects are not allowed inside a statement expression");
}
}
}
@@ -7314,107 +8293,502 @@ namespace Microsoft.Dafny
Contract.Assert(e.Thn.Type != null); // follows from postcondition of ResolveExpression
ResolveExpression(e.Els, opts);
Contract.Assert(e.Els.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.Test.Type, Type.Bool)) {
- Error(expr, "guard condition in if-then-else expression must be a boolean (instead got {0})", e.Test.Type);
- }
- if (UnifyTypes(e.Thn.Type, e.Els.Type)) {
+ ConstrainTypes(e.Test.Type, Type.Bool, expr, "guard condition in if-then-else expression must be a boolean (instead got {0})", e.Test.Type);
+ if (ConstrainTypes(e.Thn.Type, e.Els.Type, expr, "the two branches of an if-then-else expression must have the same type (got {0} and {1})", e.Thn.Type, e.Els.Type)) {
expr.Type = e.Thn.Type;
- } else {
- Error(expr, "the two branches of an if-then-else expression must have the same type (got {0} and {1})", e.Thn.Type, e.Els.Type);
}
} else if (expr is MatchExpr) {
- var me = (MatchExpr)expr;
- ResolveExpression(me.Source, opts);
- Contract.Assert(me.Source.Type != null); // follows from postcondition of ResolveExpression
- UserDefinedType sourceType = null;
- DatatypeDecl dtd = null;
- if (me.Source.Type.IsDatatype) {
- sourceType = (UserDefinedType)me.Source.Type.NormalizeExpand();
- dtd = cce.NonNull((DatatypeDecl)sourceType.ResolvedClass);
- }
- var subst = new Dictionary<TypeParameter, Type>();
- Dictionary<string, DatatypeCtor> ctors;
- if (dtd == null) {
- Error(me.Source, "the type of the match source expression must be a datatype (instead found {0})", me.Source.Type);
- ctors = null;
+ ResolveMatchExpr(expr, opts);
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
+ }
+
+ if (expr.Type == null) {
+ // some resolution error occurred
+ expr.Type = new InferredTypeProxy();
+ }
+ }
+
+ /// <summary>
+ /// Attempts to produce a let expression from the given datatype updates. Returns that let expression upon success, and null otherwise.
+ /// </summary>
+ Expression ResolveDatatypeUpdate(IToken tok, Expression root, DatatypeDecl dt, List<Tuple<IToken, string, Expression>> memberUpdates, bool sequentialUpdates, ResolveOpts opts) {
+ Contract.Requires(tok != null);
+ Contract.Requires(root != null);
+ Contract.Requires(dt != null);
+ Contract.Requires(memberUpdates != null);
+ Contract.Requires(opts != null);
+
+ // Let en = e and e(n-1) = en.Seq
+ // We're currently looking at e = e(n-1)[en.Index := en.Value]
+ // Let e(n-2) = e(n-1).Seq, e(n-3) = e(n-2).Seq, etc.
+ // Let's extract e = e0[e1.Index := e1.Value]...[en.Index := en.Value]
+ DatatypeCtor ctor = null;
+ Tuple<IToken, string, Expression> ctorSource = default(Tuple<IToken, string, Expression>); // relevant only if "ctor" is non-null
+ var memberNames = new HashSet<string>();
+ var updates = new Dictionary<Formal, Expression>();
+ foreach (var entry in memberUpdates) {
+ var destructor_str = entry.Item2;
+ if (memberNames.Contains(destructor_str)) {
+ if (sequentialUpdates) {
+ reporter.Warning(MessageSource.Resolver, entry.Item1, "update to '{0}' overwritten by another update to '{0}'", destructor_str);
+ } else {
+ reporter.Error(MessageSource.Resolver, entry.Item1, "duplicate update member '{0}'", destructor_str);
+ }
} else {
- Contract.Assert(sourceType != null); // dtd and sourceType are set together above
- ctors = datatypeCtors[dtd];
- Contract.Assert(ctors != null); // dtd should have been inserted into datatypeCtors during a previous resolution stage
+ memberNames.Add(destructor_str);
+ MemberDecl member;
+ if (!datatypeMembers[dt].TryGetValue(destructor_str, out member)) {
+ reporter.Error(MessageSource.Resolver, entry.Item1, "member '{0}' does not exist in datatype '{1}'", destructor_str, dt.Name);
+ } else {
+ var destructor = (DatatypeDestructor)member;
+ if (ctor != null && ctor != destructor.EnclosingCtor) {
+ if (sequentialUpdates) {
+ // This would eventually give rise to a verification error. However, since the 'sequentialUpdates' case is being depricated,
+ // we don't mind giving resolution error about this now.
+ }
+ reporter.Error(MessageSource.Resolver, entry.Item1, "updated datatype members must belong to the same constructor " +
+ "('{0}' belongs to '{1}' and '{2}' belongs to '{3}'", entry.Item2, destructor.EnclosingCtor.Name, ctorSource.Item2, ctor.Name);
+ } else {
+ updates.Add(destructor.CorrespondingFormal, entry.Item3);
+ ctor = destructor.EnclosingCtor;
+ ctorSource = entry;
+ }
+ }
+ }
+ }
+
+ if (ctor != null) {
+ // Rewrite an update of the form "dt[dtor := E]" to be "let d' := dt in dtCtr(E, d'.dtor2, d'.dtor3,...)"
+ // Wrapping it in a let expr avoids exponential growth in the size of the expression
+ // More generally, rewrite "E0[dtor1 := E1][dtor2 := E2]...[dtorn := En]" where "E0" is "root" to
+ // "let d' := E0 in dtCtr(...mixtures of Ek and d'.dtorj...)"
- // build the type-parameter substitution map for this use of the datatype
- for (int i = 0; i < dtd.TypeArgs.Count; i++) {
- subst.Add(dtd.TypeArgs[i], sourceType.TypeArgs[i]);
+ // Create a unique name for d', the variable we introduce in the let expression
+ var tmpName = FreshTempVarName("dt_update_tmp#", opts.codeContext);
+ var tmpVarIdExpr = new IdentifierExpr(new AutoGeneratedToken(tok), tmpName);
+ var tmpVarBv = new BoundVar(new AutoGeneratedToken(tok), tmpName, root.Type);
+
+ // Build the arguments to the datatype constructor, using the updated value in the appropriate slot
+ var ctor_args = new List<Expression>();
+ foreach (Formal d in ctor.Formals) {
+ Expression v;
+ if (updates.TryGetValue(d, out v)) {
+ ctor_args.Add(v);
+ } else {
+ ctor_args.Add(new ExprDotName(tok, tmpVarIdExpr, d.Name, null));
}
}
- ISet<string> memberNamesUsed = new HashSet<string>();
- expr.Type = new InferredTypeProxy();
- foreach (MatchCaseExpr mc in me.Cases) {
- DatatypeCtor ctor = null;
- if (ctors != null) {
- Contract.Assert(dtd != null);
- if (!ctors.TryGetValue(mc.Id, out ctor)) {
- Error(mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name);
+ DatatypeValue ctor_call = new DatatypeValue(tok, ctor.EnclosingDatatype.Name, ctor.Name, ctor_args);
+
+ CasePattern tmpVarPat = new CasePattern(tok, tmpVarBv);
+ LetExpr let = new LetExpr(tok, new List<CasePattern>() { tmpVarPat }, new List<Expression>() { root }, ctor_call, true);
+
+ ResolveExpression(let, opts);
+ return let;
+ }
+ return null;
+ }
+
+ void ResolveMatchExpr(Expression expr, ResolveOpts opts) {
+ var me = (MatchExpr)expr;
+ DesugarMatchExprWithTupleExpression(me);
+
+ ResolveExpression(me.Source, opts);
+ Contract.Assert(me.Source.Type != null); // follows from postcondition of ResolveExpression
+ UserDefinedType sourceType = null;
+ DatatypeDecl dtd = null;
+ if (me.Source.Type.IsDatatype) {
+ sourceType = (UserDefinedType)me.Source.Type.NormalizeExpand();
+ dtd = cce.NonNull((DatatypeDecl)sourceType.ResolvedClass);
+ }
+ var subst = new Dictionary<TypeParameter, Type>();
+ Dictionary<string, DatatypeCtor> ctors;
+ if (dtd == null) {
+ reporter.Error(MessageSource.Resolver, me.Source, "the type of the match source expression must be a datatype (instead found {0})", me.Source.Type);
+ ctors = null;
+ } else {
+ Contract.Assert(sourceType != null); // dtd and sourceType are set together above
+ ctors = datatypeCtors[dtd];
+ Contract.Assert(ctors != null); // dtd should have been inserted into datatypeCtors during a previous resolution stage
+
+ // build the type-parameter substitution map for this use of the datatype
+ for (int i = 0; i < dtd.TypeArgs.Count; i++) {
+ subst.Add(dtd.TypeArgs[i], sourceType.TypeArgs[i]);
+ }
+ }
+
+ // convert CasePattern in MatchCaseExpr to BoundVar and flatten the MatchCaseExpr.
+ List<Tuple<CasePattern, BoundVar>> patternSubst = new List<Tuple<CasePattern, BoundVar>>();
+ if (dtd != null) {
+ DesugarMatchCaseExpr(me, dtd, patternSubst, opts.codeContext);
+ }
+
+ ISet<string> memberNamesUsed = new HashSet<string>();
+ expr.Type = new InferredTypeProxy();
+ foreach (MatchCaseExpr mc in me.Cases) {
+ DatatypeCtor ctor = null;
+ if (ctors != null) {
+ Contract.Assert(dtd != null);
+ if (!ctors.TryGetValue(mc.Id, out ctor)) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name);
+ } else {
+ Contract.Assert(ctor != null); // follows from postcondition of TryGetValue
+ mc.Ctor = ctor;
+ if (ctor.Formals.Count != mc.Arguments.Count) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count);
+ }
+ if (memberNamesUsed.Contains(mc.Id)) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "member {0} appears in more than one case", mc.Id);
} else {
- Contract.Assert(ctor != null); // follows from postcondition of TryGetValue
- mc.Ctor = ctor;
- if (ctor.Formals.Count != mc.Arguments.Count) {
- Error(mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count);
- }
- if (memberNamesUsed.Contains(mc.Id)) {
- Error(mc.tok, "member {0} appears in more than one case", mc.Id);
- } else {
- memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used
- }
+ memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used
}
}
- scope.PushMarker();
- int i = 0;
+ }
+ scope.PushMarker();
+ int i = 0;
+ if (mc.Arguments != null) {
foreach (BoundVar v in mc.Arguments) {
- if (!scope.Push(v.Name, v)) {
- Error(v, "Duplicate parameter name: {0}", v.Name);
- }
+ scope.Push(v.Name, v);
ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
if (ctor != null && i < ctor.Formals.Count) {
Formal formal = ctor.Formals[i];
Type st = SubstType(formal.Type, subst);
- if (!UnifyTypes(v.Type, st)) {
- Error(expr, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st);
- }
+ ConstrainTypes(v.Type, st,
+ expr, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st);
v.IsGhost = formal.IsGhost;
+
+ // update the type of the boundvars in the MatchCaseToken
+ if (v.tok is MatchCaseToken) {
+ MatchCaseToken mt = (MatchCaseToken)v.tok;
+ foreach (Tuple<IToken, BoundVar, bool> entry in mt.varList) {
+ UnifyTypes(entry.Item2.Type, v.Type); // TODO: What to do if this unification fails? Or can it? --KRML
+ }
+ }
}
i++;
}
+ }
+ ResolveExpression(mc.Body, opts);
+ // substitute body to replace the case pat with v. This needs to happen
+ // after the body is resolved so we can scope the bv correctly.
+ if (patternSubst.Count > 0) {
+ MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(patternSubst);
+ mc.UpdateBody(cloner.CloneExpr(mc.Body));
+ // resolve it again since we just cloned it.
ResolveExpression(mc.Body, opts);
- Contract.Assert(mc.Body.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(expr.Type, mc.Body.Type)) {
- Error(mc.Body.tok, "type of case bodies do not agree (found {0}, previous types {1})", mc.Body.Type, expr.Type);
+ }
+
+ Contract.Assert(mc.Body.Type != null); // follows from postcondition of ResolveExpression
+ ConstrainTypes(expr.Type, mc.Body.Type, mc.Body.tok, "type of case bodies do not agree (found {0}, previous types {1})", mc.Body.Type, expr.Type);
+ scope.PopMarker();
+ }
+ if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
+ // We could complain about the syntactic omission of constructors:
+ // reporter.Error(MessageSource.Resolver, expr, "match expression does not cover all constructors");
+ // but instead we let the verifier do a semantic check.
+ // So, for now, record the missing constructors:
+ foreach (var ctr in dtd.Ctors) {
+ if (!memberNamesUsed.Contains(ctr.Name)) {
+ me.MissingCases.Add(ctr);
+ }
+ }
+ Contract.Assert(memberNamesUsed.Count + me.MissingCases.Count == dtd.Ctors.Count);
+ }
+ }
+
+ /*
+ * Convert
+ * match (x, y)
+ * case (Zero, _) => Zero
+ * case (Suc(_), Zero) => x
+ * case (Suc(a), Suc(b)) => minus(a, b)
+ * To:
+ * match x
+ * case Zero => match y
+ * case _ => zero
+ * case Suc(_) => match y
+ * case Zero => x
+ * case Suc(a) => match y
+ * case (b) => minus(a,b)
+ */
+ private void DesugarMatchExprWithTupleExpression(MatchExpr me) {
+ // (x, y) is treated as a 2-tuple constructor
+ if (me.Source is DatatypeValue) {
+ var e = (DatatypeValue)me.Source;
+ if (e.Arguments.Count < 1) {
+ reporter.Error(MessageSource.Resolver, me.tok, "match source tuple needs at least 1 argument");
+ } else {
+ Expression source = e.Arguments[0];
+ List<MatchCaseExpr> cases = new List<MatchCaseExpr>();
+ foreach (MatchCaseExpr mc in me.Cases) {
+ if (mc.CasePatterns == null || mc.CasePatterns.Count != e.Arguments.Count) {
+ reporter.Error(MessageSource.Resolver, mc.tok, "case arguments count does not match source arguments count");
+ } else {
+ CasePattern cp = mc.CasePatterns[0];
+ List<CasePattern> patterns;
+ if (cp.Arguments != null) {
+ patterns = cp.Arguments;
+ } else {
+ patterns = new List<CasePattern>();
+ }
+
+ Expression body = mc.Body;
+ for (int i = e.Arguments.Count; 1 <= --i; ) {
+ // others go into the body
+ body = CreateMatchCaseExprBody(me.tok, e.Arguments[i], mc.CasePatterns[i], body);
+ }
+ cases.Add(new MatchCaseExpr(cp.tok, cp.Id, patterns, body));
+ }
}
- scope.PopMarker();
+ me.UpdateSource(source);
+ me.UpdateCases(cases);
}
- if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {
- // We could complain about the syntactic omission of constructors:
- // Error(expr, "match expression does not cover all constructors");
- // but instead we let the verifier do a semantic check.
- // So, for now, record the missing constructors:
- foreach (var ctr in dtd.Ctors) {
- if (!memberNamesUsed.Contains(ctr.Name)) {
- me.MissingCases.Add(ctr);
+ }
+ }
+
+ Expression CreateMatchCaseExprBody(Boogie.IToken tok, Expression source, CasePattern cp, Expression body) {
+ List<MatchCaseExpr> cases = new List<MatchCaseExpr>();
+ List<CasePattern> patterns;
+ if (cp.Var != null) {
+ var bv = cp.Var;
+ if (LocalVariable.HasWildcardName(bv)) {
+ return body;
+ } else {
+ patterns = new List<CasePattern>();
+ }
+ } else {
+ patterns = cp.Arguments;
+ }
+ cases.Add(new MatchCaseExpr(cp.tok, cp.Id, patterns, body));
+ return new MatchExpr(tok, source, cases, false);
+ }
+
+ /*
+ * Convert
+ * match xs
+ * case Cons(y, Cons(z, zs)) => last(Cons(z, zs))
+ * case Cons(y, Nil) => y
+ * To
+ * match xs
+ * case Cons(y, ys) => match ys
+ * case Nil => y
+ * case Cons(z, zs) => last(ys)
+ * */
+ void DesugarMatchCaseExpr(MatchExpr me, DatatypeDecl dtd, List<Tuple<CasePattern, BoundVar>> patterns, ICodeContext codeContext) {
+ Contract.Assert(dtd != null);
+ Dictionary<string, DatatypeCtor> ctors = datatypeCtors[dtd];
+ if (ctors == null) {
+ // no constructors, there is no need to desugar
+ return;
+ }
+
+ Type type = new InferredTypeProxy();
+ string name = FreshTempVarName("_mc#", codeContext);
+ foreach (MatchCaseExpr mc in me.Cases) {
+ if (mc.Arguments != null) {
+ // already desugared. This happens during the second pass resolver after cloning.
+ Contract.Assert(mc.CasePatterns == null);
+ return;
+ }
+
+ BoundVar sourceVar = new BoundVar(new MatchCaseToken(me.tok), name, type);
+ Contract.Assert(mc.Arguments == null);
+ Contract.Assert(mc.CasePatterns != null);
+ Contract.Assert(ctors != null);
+ DatatypeCtor ctor = null;
+ if (ctors.TryGetValue(mc.Id, out ctor)) {
+ scope.PushMarker();
+ foreach (CasePattern pat in mc.CasePatterns) {
+ FindDuplicateIdentifier(pat, ctors, true);
+ }
+ List<BoundVar> arguments = new List<BoundVar>();
+ foreach (CasePattern pat in mc.CasePatterns) {
+ if (pat.Var != null) {
+ BoundVar v = pat.Var;
+ arguments.Add(v);
+ } else {
+ DesugarMatchCasePattern(mc, pat, sourceVar);
+ patterns.Add(new Tuple<CasePattern, BoundVar>(pat, sourceVar));
+ arguments.Add(sourceVar);
}
}
- Contract.Assert(memberNamesUsed.Count + me.MissingCases.Count == dtd.Ctors.Count);
+ mc.Arguments = arguments;
+ mc.CasePatterns = null;
+ scope.PopMarker();
+ }
+ }
+
+
+ List<MatchCaseExpr> newCases = new List<MatchCaseExpr>();
+
+ // need to consolidate the cases.
+ // Convert
+ // match xs
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Cons((z, zs) => body
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Nil => y
+ // into
+ // match xs
+ // case Cons(y, #mc#0) => match #mc#0
+ // case Cons((z, zs) => body
+ // case Nil => y
+ bool thingsChanged = false;
+ Dictionary<string, MatchCaseExpr> caseMap = new Dictionary<string, MatchCaseExpr>();
+ List<MatchCaseExpr> mcWithWildCard = new List<MatchCaseExpr>();
+ foreach (MatchCaseExpr mc in me.Cases) {
+ // check each CasePattern to see if it has wildcard.
+ if (CaseExprHasWildCard(mc)) {
+ mcWithWildCard.Add(mc);
+ } else {
+ thingsChanged |= CombineMatchCaseExpr(mc, newCases, caseMap, codeContext);
+ }
+ }
+
+ foreach (MatchCaseExpr mc in mcWithWildCard) {
+ // now process with cases with wildcard
+ thingsChanged |= CombineMatchCaseExpr(mc, newCases, caseMap, codeContext);
+ }
+
+ if (thingsChanged) {
+ me.UpdateCases(newCases);
+ }
+ }
+
+ void DesugarMatchCasePattern(MatchCaseExpr mc, CasePattern pat, BoundVar v) {
+ // convert
+ // case Cons(y, Cons(z, zs)) => body
+ // to
+ // case Cons(y, #mc#) => match #mc#
+ // case Cons(z, zs) => body
+
+ Expression source = new NameSegment(new AutoGeneratedToken(pat.tok), v.Name, null);
+ List<MatchCaseExpr> cases = new List<MatchCaseExpr>();
+ cases.Add(new MatchCaseExpr(pat.tok, pat.Id, pat.Arguments == null ? new List<CasePattern>() : pat.Arguments, mc.Body));
+ MatchExpr e = new MatchExpr(pat.tok, source, cases, false);
+ mc.UpdateBody(e);
+ }
+
+
+ bool CaseExprHasWildCard(MatchCase mc) {
+ if (mc.Arguments != null) {
+ foreach (BoundVar bv in mc.Arguments) {
+ if (LocalVariable.HasWildcardName(bv)) {
+ return true;
+ }
}
+ }
+ return false;
+ }
+ bool CombineMatchCaseExpr(MatchCaseExpr mc, List<MatchCaseExpr> newCases, Dictionary<string, MatchCaseExpr> caseMap, ICodeContext codeContext) {
+ bool thingsChanged = false;
+ MatchCaseExpr old_mc;
+ if (caseMap.TryGetValue(mc.Id, out old_mc)) {
+ // already has a case with the same ctor, try to consolidate the body.
+ if (SameMatchCaseExpr(old_mc, mc, codeContext)) {
+ MatchExpr old = (MatchExpr)old_mc.Body;
+ MatchExpr current = (MatchExpr)mc.Body;
+ foreach (MatchCaseExpr c in current.Cases) {
+ old.Cases.Add(c);
+ }
+ // add the token from mc to old_mc so the identifiers will show correctly in the IDE
+ List<BoundVar> arguments = new List<BoundVar>();
+ Contract.Assert(old_mc.Arguments.Count == mc.Arguments.Count);
+ for (int i = 0; i < old_mc.Arguments.Count; i++) {
+ var bv = old_mc.Arguments[i];
+ MatchCaseToken mcToken;
+ if (!(bv.tok is MatchCaseToken)) {
+ // create a MatchCaseToken
+ mcToken = new MatchCaseToken(bv.tok);
+ // clone the bv but with the MatchCaseToken
+ var bvNew = new BoundVar(mcToken, bv.Name, bv.Type);
+ bvNew.IsGhost = bv.IsGhost;
+ arguments.Add(bvNew);
+ } else {
+ mcToken = (MatchCaseToken)bv.tok;
+ arguments.Add(bv);
+ }
+ mcToken.AddVar(bv.tok, bv, true);
+ mcToken.AddVar(mc.Arguments[i].tok, mc.Arguments[i], true);
+ }
+ old_mc.Arguments = arguments;
+ thingsChanged = true;
+ } else {
+ // duplicate cases, do nothing for now. The error will be reported during resolving
+ }
} else {
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
+ // it is a new case.
+ newCases.Add(mc);
+ caseMap.Add(mc.Id, mc);
}
+ return thingsChanged;
+ }
- if (expr.Type == null) {
- // some resolution error occurred
- expr.Type = new InferredTypeProxy();
+
+ bool SameMatchCaseExpr(MatchCaseExpr one, MatchCaseExpr other, ICodeContext codeContext) {
+ // this method is called after all the CasePattern in the match cases are converted
+ // into BoundVars.
+ Contract.Assert(one.CasePatterns == null && one.Arguments != null);
+ Contract.Assert(other.CasePatterns == null && other.Arguments != null);
+ // In order to combine the two match cases, the bodies need to be a MatchExpr and
+ // the arguments and the source of the body are the same.
+ // We do string equals since they should be in the same scope.
+ if (one.Arguments.Count != other.Arguments.Count) {
+ return false;
+ }
+ if (!(one.Body is MatchExpr) || !(other.Body is MatchExpr)) {
+ return false;
+ }
+ var source1 = ((MatchExpr)one.Body).Source;
+ var source2 = ((MatchExpr)other.Body).Source;
+ if (!(source1 is NameSegment) || !(source2 is NameSegment)) {
+ return false;
+ }
+ if (!((NameSegment)source1).Name.Equals(((NameSegment)source2).Name)) {
+ return false;
+ }
+ for (int i = 0; i < one.Arguments.Count; i++) {
+ BoundVar bv1 = one.Arguments[i];
+ BoundVar bv2 = other.Arguments[i];
+ if (!LocalVariable.HasWildcardName(bv1) && !LocalVariable.HasWildcardName(bv2)) {
+ if (!bv1.Name.Equals(bv2.Name)) {
+ // need to substitute bv2 with bv1 in the matchstmt body
+ // what if match body already has the bv?? need to make a new bv
+ Type type = new InferredTypeProxy();
+ string name = FreshTempVarName("_mc#", codeContext);
+ MatchCaseToken mcToken = new MatchCaseToken(one.tok);
+ BoundVar bv = new BoundVar(mcToken, name, type);
+ mcToken.AddVar(bv1.tok, bv1, true);
+ mcToken.AddVar(bv2.tok, bv2, true);
+ // substitute the appeareance of old bv with the new bv in the match case
+ SubstituteMatchCaseBoundVar(one, bv1, bv);
+ SubstituteMatchCaseBoundVar(other, bv2, bv);
+ }
+ }
+ }
+ return true;
+ }
+
+ void SubstituteMatchCaseBoundVar(MatchCaseExpr mc, BoundVar oldBv, BoundVar newBv) {
+ List<BoundVar> arguments = new List<BoundVar>();
+ for (int i = 0; i < mc.Arguments.Count; i++) {
+ BoundVar bv = mc.Arguments[i];
+ if (bv == oldBv) {
+ arguments.Add(newBv);
+ } else {
+ arguments.Add(bv);
+ }
}
+ mc.Arguments = arguments;
+
+ // substitue the oldBv with newBv in the body
+ MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(oldBv, newBv);
+ Expression clone = cloner.CloneExpr(mc.Body);
+ mc.UpdateBody(clone);
}
void ResolveCasePattern(CasePattern pat, Type sourceType, ICodeContext context) {
@@ -7431,29 +8805,30 @@ namespace Microsoft.Dafny
// Find the constructor in the given datatype
// If what was parsed was just an identifier, we will interpret it as a datatype constructor, if possible
DatatypeCtor ctor = null;
- if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy && dtd != null)) {
- if (datatypeCtors[dtd].TryGetValue(pat.Id, out ctor)) {
- pat.Ctor = ctor;
- pat.Var = null;
+ if (dtd != null) {
+ if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy)) {
+ if (datatypeCtors[dtd].TryGetValue(pat.Id, out ctor)) {
+ pat.Ctor = ctor;
+ pat.Var = null;
+ }
}
}
+
if (pat.Var != null) {
// this is a simple resolution
var v = pat.Var;
ResolveType(v.tok, v.Type, context, ResolveTypeOptionEnum.InferTypeProxies, null);
- if (!UnifyTypes(v.Type, sourceType)) {
- Error(v.tok, "type of corresponding source/RHS ({0}) does not match type of bound variable ({1})", sourceType, v.Type);
- }
+ ConstrainTypes(v.Type, sourceType, v.tok, "type of corresponding source/RHS ({0}) does not match type of bound variable ({1})", sourceType, v.Type);
pat.AssembleExpr(null);
} else if (dtd == null) {
- Error(pat.tok, "to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})", sourceType);
+ reporter.Error(MessageSource.Resolver, pat.tok, "to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})", sourceType);
} else if (ctor == null) {
- Error(pat.tok, "constructor {0} does not exist in datatype {1}", pat.Id, dtd.Name);
+ reporter.Error(MessageSource.Resolver, pat.tok, "constructor {0} does not exist in datatype {1}", pat.Id, dtd.Name);
} else {
var argCount = pat.Arguments == null ? 0 : pat.Arguments.Count;
if (ctor.Formals.Count != argCount) {
- Error(pat.tok, "pattern for constructor {0} has wrong number of formals (found {1}, expected {2})", pat.Id, argCount, ctor.Formals.Count);
+ reporter.Error(MessageSource.Resolver, pat.tok, "pattern for constructor {0} has wrong number of formals (found {1}, expected {2})", pat.Id, argCount, ctor.Formals.Count);
}
// build the type-parameter substitution map for this use of the datatype
Contract.Assert(dtd.TypeArgs.Count == udt.TypeArgs.Count); // follows from the type previously having been successfully resolved
@@ -7463,13 +8838,15 @@ namespace Microsoft.Dafny
}
// recursively call ResolveCasePattern on each of the arguments
var j = 0;
- foreach (var arg in pat.Arguments) {
- if (j < ctor.Formals.Count) {
- var formal = ctor.Formals[j];
- Type st = SubstType(formal.Type, subst);
- ResolveCasePattern(arg, st, context);
+ if (pat.Arguments != null) {
+ foreach (var arg in pat.Arguments) {
+ if (j < ctor.Formals.Count) {
+ var formal = ctor.Formals[j];
+ Type st = SubstType(formal.Type, subst);
+ ResolveCasePattern(arg, st, context);
+ }
+ j++;
}
- j++;
}
if (j == ctor.Formals.Count) {
pat.AssembleExpr(udt.TypeArgs);
@@ -7502,12 +8879,12 @@ namespace Microsoft.Dafny
Contract.Requires(!expr.WasResolved());
Contract.Requires(opts != null);
Contract.Ensures(Contract.Result<Expression>() == null || args != null);
-
+
if (expr.OptTypeArguments != null) {
foreach (var ty in expr.OptTypeArguments) {
ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
if (ty.IsSubrangeType) {
- Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
+ reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
}
}
}
@@ -7530,7 +8907,7 @@ namespace Microsoft.Dafny
if (v != null) {
// ----- 0. local variable, parameter, or bound variable
if (expr.OptTypeArguments != null) {
- Error(expr.tok, "variable '{0}' does not take any type parameters", expr.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "variable '{0}' does not take any type parameters", expr.Name);
}
var rr = new IdentifierExpr(expr.tok, expr.Name);
rr.Var = v; rr.Type = v.Type;
@@ -7539,10 +8916,10 @@ namespace Microsoft.Dafny
// ----- 1. member of the enclosing class
Expression receiver;
if (member.IsStatic) {
- receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
+ receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true);
} else {
if (!scope.AllowInstance) {
- Error(expr.tok, "'this' is not allowed in a 'static' context");
+ reporter.Error(MessageSource.Resolver, expr.tok, "'this' is not allowed in a 'static' context"); //TODO: Rephrase this
// nevertheless, set "receiver" to a value so we can continue resolution
}
receiver = new ImplicitThisExpr(expr.tok);
@@ -7553,10 +8930,10 @@ namespace Microsoft.Dafny
// ----- 2. datatype constructor
if (pair.Item2) {
// there is more than one constructor with this name
- Error(expr.tok, "the name '{0}' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", expr.Name, pair.Item1.EnclosingDatatype.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "the name '{0}' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", expr.Name, pair.Item1.EnclosingDatatype.Name);
} else {
if (expr.OptTypeArguments != null) {
- Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.Name);
}
var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, expr.Name, args ?? new List<Expression>());
ResolveDatatypeValue(opts, rr, pair.Item1.EnclosingDatatype);
@@ -7571,7 +8948,7 @@ namespace Microsoft.Dafny
// ----- 3. Member of the enclosing module
if (decl is AmbiguousTopLevelDecl) {
var ad = (AmbiguousTopLevelDecl)decl;
- Error(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.Name, ad.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.Name, ad.ModuleNames());
} else {
// We have found a module name or a type name, neither of which is an expression. However, the NameSegment we're
// looking at may be followed by a further suffix that makes this into an expresion. We postpone the rest of the
@@ -7585,15 +8962,15 @@ namespace Microsoft.Dafny
Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default
if (member is AmbiguousMemberDecl) {
var ambiguousMember = (AmbiguousMemberDecl)member;
- Error(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.Name, ambiguousMember.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.Name, ambiguousMember.ModuleNames());
} else {
- var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
+ var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true);
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
} else {
// ----- None of the above
- Error(expr.tok, "unresolved identifier: {0}", expr.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "unresolved identifier: {0}", expr.Name);
}
if (r == null) {
@@ -7625,7 +9002,7 @@ namespace Microsoft.Dafny
foreach (var ty in expr.OptTypeArguments) {
ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments);
if (ty.IsSubrangeType) {
- Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
+ reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
}
}
}
@@ -7649,7 +9026,7 @@ namespace Microsoft.Dafny
if (expr.OptTypeArguments == null) {
r = new Resolver_IdentifierExpr(expr.tok, tp);
} else {
- Error(expr.tok, "Type parameter expects no type arguments: {0}", expr.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "Type parameter expects no type arguments: {0}", expr.Name);
}
#if ASYNC_TASK_TYPES // At the moment, there is no way for a class member to part of a type name, but this changes with async task types
} else if (currentClass != null && classMembers.TryGetValue(currentClass, out members) && members.TryGetValue(expr.Name, out member)) {
@@ -7659,7 +9036,7 @@ namespace Microsoft.Dafny
receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
} else {
if (!scope.AllowInstance) {
- Error(expr.tok, "'this' is not allowed in a 'static' context");
+ reporter.Error(MessageSource.Resolver, expr.tok, "'this' is not allowed in a 'static' context");
// nevertheless, set "receiver" to a value so we can continue resolution
}
receiver = new ImplicitThisExpr(expr.tok);
@@ -7671,7 +9048,7 @@ namespace Microsoft.Dafny
// ----- 2. Member of the enclosing module
if (decl is AmbiguousTopLevelDecl) {
var ad = (AmbiguousTopLevelDecl)decl;
- Error(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.Name, ad.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.Name, ad.ModuleNames());
} else {
// We have found a module name or a type name, neither of which is a type expression. However, the NameSegment we're
// looking at may be followed by a further suffix that makes this into a type expresion. We postpone the rest of the
@@ -7685,21 +9062,15 @@ namespace Microsoft.Dafny
// ----- 3. static member of the enclosing module
Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default
if (ReallyAmbiguousThing(ref member)) {
- Error(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.Name, ((AmbiguousMemberDecl)member).ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.Name, ((AmbiguousMemberDecl)member).ModuleNames());
} else {
var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
#endif
- } else if (option.Opt == ResolveTypeOptionEnum.AllowPrefixExtend && expr.OptTypeArguments == null) {
- // it woulc plausibly be a type parameter, but isn't; we will declare it automatically
- tp = new TypeParameter(expr.tok, expr.Name, defaultTypeArguments.Count, option.Parent);
- defaultTypeArguments.Add(tp);
- r = new Resolver_IdentifierExpr(expr.tok, tp);
- allTypeParameters.Push(expr.Name, tp);
} else {
// ----- None of the above
- Error(expr.tok, "Undeclared top-level type or type parameter: {0} (did you forget to qualify a name?)", expr.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "Undeclared top-level type or type parameter: {0} (did you forget to qualify a name or declare a module import 'opened?')", expr.Name);
}
if (r == null) {
@@ -7720,7 +9091,7 @@ namespace Microsoft.Dafny
if (optTypeArguments != null) {
// type arguments were supplied; they must be equal in number to those expected
if (n != decl.TypeArgs.Count) {
- Error(tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", n, decl.TypeArgs.Count, decl.WhatKind, name);
+ reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", n, decl.TypeArgs.Count, decl.WhatKind, name);
}
}
List<Type> tpArgs = new List<Type>();
@@ -7772,7 +9143,7 @@ namespace Microsoft.Dafny
foreach (var ty in expr.OptTypeArguments) {
ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);
if (ty.IsSubrangeType) {
- Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
+ reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
}
}
}
@@ -7795,10 +9166,10 @@ namespace Microsoft.Dafny
// ----- 0. datatype constructor
if (pair.Item2) {
// there is more than one constructor with this name
- Error(expr.tok, "the name '{0}' denotes a datatype constructor in module {2}, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", expr.SuffixName, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "the name '{0}' denotes a datatype constructor in module {2}, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", expr.SuffixName, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name);
} else {
if (expr.OptTypeArguments != null) {
- Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName);
}
var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, expr.SuffixName, args ?? new List<Expression>());
ResolveExpression(rr, opts);
@@ -7813,7 +9184,7 @@ namespace Microsoft.Dafny
// ----- 1. Member of the specified module
if (decl is AmbiguousTopLevelDecl) {
var ad = (AmbiguousTopLevelDecl)decl;
- Error(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.SuffixName, ad.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.SuffixName, ad.ModuleNames());
} else {
// We have found a module name or a type name, neither of which is an expression. However, the ExprDotName we're
// looking at may be followed by a further suffix that makes this into an expresion. We postpone the rest of the
@@ -7826,13 +9197,13 @@ namespace Microsoft.Dafny
Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default
if (member is AmbiguousMemberDecl) {
var ambiguousMember = (AmbiguousMemberDecl)member;
- Error(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.SuffixName, ambiguousMember.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.SuffixName, ambiguousMember.ModuleNames());
} else {
- var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
+ var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true);
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
} else {
- Error(expr.tok, "unresolved identifier: {0}", expr.SuffixName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "unresolved identifier: {0}", expr.SuffixName);
}
} else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {
@@ -7851,10 +9222,10 @@ namespace Microsoft.Dafny
Dictionary<string, MemberDecl> members;
if (classMembers.TryGetValue(cd, out members) && members.TryGetValue(expr.SuffixName, out member)) {
if (!member.IsStatic) {
- Error(expr.tok, "accessing member '{0}' requires an instance expression", expr.SuffixName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "accessing member '{0}' requires an instance expression", expr.SuffixName); //TODO Unify with similar error messages
// nevertheless, continue creating an expression that approximates a correct one
}
- var receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)ty.NormalizeExpand(), (ClassDecl)member.EnclosingClass);
+ var receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)ty.NormalizeExpand(), (ClassDecl)member.EnclosingClass, false);
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
} else if (ty.IsDatatype) {
@@ -7864,7 +9235,7 @@ namespace Microsoft.Dafny
DatatypeCtor ctor;
if (datatypeCtors.TryGetValue(dt, out members) && members.TryGetValue(expr.SuffixName, out ctor)) {
if (expr.OptTypeArguments != null) {
- Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName);
}
var rr = new DatatypeValue(expr.tok, ctor.EnclosingDatatype.Name, expr.SuffixName, args ?? new List<Expression>());
ResolveDatatypeValue(opts, rr, ctor.EnclosingDatatype);
@@ -7877,19 +9248,20 @@ namespace Microsoft.Dafny
}
}
if (r == null) {
- Error(expr.tok, "member '{0}' does not exist in type '{1}'", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "member '{0}' does not exist in type '{1}'", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);
}
} else if (lhs != null) {
// ----- 4. Look up name in the type of the Lhs
+ bool classMemberOnly = UserDefinedType.DenotesClass(expr.Lhs.Type) == null ? false : true;
NonProxyType nptype;
- member = ResolveMember(expr.tok, expr.Lhs.Type, expr.SuffixName, out nptype);
+ member = ResolveMember(expr.tok, expr.Lhs.Type, expr.SuffixName, out nptype, classMemberOnly);
if (member != null) {
Expression receiver;
if (!member.IsStatic) {
receiver = expr.Lhs;
} else {
Contract.Assert(expr.Lhs.Type.IsRefType); // only reference types have static methods
- receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)expr.Lhs.Type.NormalizeExpand(), (ClassDecl)member.EnclosingClass);
+ receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)expr.Lhs.Type.NormalizeExpand(), (ClassDecl)member.EnclosingClass, false);
}
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
@@ -7937,7 +9309,7 @@ namespace Microsoft.Dafny
foreach (var ty in expr.OptTypeArguments) {
ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments);
if (ty.IsSubrangeType) {
- Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
+ reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type");
}
}
}
@@ -7956,7 +9328,7 @@ namespace Microsoft.Dafny
// ----- 0. Member of the specified module
if (decl is AmbiguousTopLevelDecl) {
var ad = (AmbiguousTopLevelDecl)decl;
- Error(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.SuffixName, ad.ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.SuffixName, ad.ModuleNames());
} else {
// We have found a module name or a type name. We create a temporary expression that will never be seen by the compiler
// or verifier, just to have a placeholder where we can recorded what we have found.
@@ -7967,14 +9339,14 @@ namespace Microsoft.Dafny
// ----- 1. static member of the specified module
Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default
if (ReallyAmbiguousThing(ref member)) {
- Error(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.SuffixName, ((AmbiguousMemberDecl)member).ModuleNames());
+ reporter.Error(MessageSource.Resolver, expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.SuffixName, ((AmbiguousMemberDecl)member).ModuleNames());
} else {
var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);
r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);
}
#endif
} else {
- Error(expr.tok, "module '{0}' does not declare a type '{1}'", ri.Decl.Name, expr.SuffixName);
+ reporter.Error(MessageSource.Resolver, expr.tok, "module '{0}' does not declare a type '{1}'", ri.Decl.Name, expr.SuffixName);
}
} else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {
@@ -7990,7 +9362,7 @@ namespace Microsoft.Dafny
return new ResolveTypeReturn(ty, expr);
}
if (r == null) {
- Error(expr.tok, "member '{0}' does not exist in type '{1}' or cannot be part of type name", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);
+ reporter.Error(MessageSource.Resolver, expr.tok, "member '{0}' does not exist in type '{1}' or cannot be part of type name", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);
}
}
@@ -8027,14 +9399,14 @@ namespace Microsoft.Dafny
if (member is Field) {
if (optTypeArguments != null) {
- Error(tok, "a field ({0}) does not take any type arguments (got {1})", member.Name, optTypeArguments.Count);
+ reporter.Error(MessageSource.Resolver, tok, "a field ({0}) does not take any type arguments (got {1})", member.Name, optTypeArguments.Count);
}
rr.Type = SubstType(((Field)member).Type, subst);
} else if (member is Function) {
var fn = (Function)member;
int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count;
if (optTypeArguments != null && suppliedTypeArguments != fn.TypeArgs.Count) {
- Error(tok, "function '{0}' expects {1} type arguments (got {2})", member.Name, fn.TypeArgs.Count, suppliedTypeArguments);
+ reporter.Error(MessageSource.Resolver, tok, "function '{0}' expects {1} type arguments (got {2})", member.Name, fn.TypeArgs.Count, suppliedTypeArguments);
}
rr.TypeApplication = new List<Type>();
if (udt != null && udt.ResolvedClass != null) {
@@ -8052,11 +9424,11 @@ namespace Microsoft.Dafny
var m = (Method)member;
if (!allowMethodCall) {
// it's a method and method calls are not allowed in the given context
- Error(tok, "expression is not allowed to invoke a method ({0})", member.Name);
+ reporter.Error(MessageSource.Resolver, tok, "expression is not allowed to invoke a method ({0})", member.Name);
}
int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count;
if (optTypeArguments != null && suppliedTypeArguments != m.TypeArgs.Count) {
- Error(tok, "method '{0}' expects {1} type arguments (got {2})", member.Name, m.TypeArgs.Count, suppliedTypeArguments);
+ reporter.Error(MessageSource.Resolver, tok, "method '{0}' expects {1} type arguments (got {2})", member.Name, m.TypeArgs.Count, suppliedTypeArguments);
}
rr.TypeApplication = new List<Type>();
if (udt != null && udt.ResolvedClass != null) {
@@ -8101,7 +9473,7 @@ namespace Microsoft.Dafny
Contract.Requires(opts != null);
Contract.Ensures(Contract.Result<MethodCallInformation>() == null || allowMethodCall);
Expression r = null; // upon success, the expression to which the ApplySuffix resolves
- var errorCount = ErrorCount;
+ var errorCount = reporter.Count(ErrorLevel.Error);
if (e.Lhs is NameSegment) {
r = ResolveNameSegment((NameSegment)e.Lhs, true, e.Args, opts, allowMethodCall);
// note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args
@@ -8119,18 +9491,18 @@ namespace Microsoft.Dafny
if (fnType == null) {
var lhs = e.Lhs.Resolved;
if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Module) {
- Error(e.tok, "name of module ({0}) is used as a function", ((Resolver_IdentifierExpr)lhs).Decl.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a function", ((Resolver_IdentifierExpr)lhs).Decl.Name);
} else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {
// It may be a conversion expression
var ri = (Resolver_IdentifierExpr)lhs;
if (ri.TypeParamDecl != null) {
- Error(e.tok, "name of type parameter ({0}) is used as a function", ri.TypeParamDecl.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of type parameter ({0}) is used as a function", ri.TypeParamDecl.Name);
} else {
var decl = ri.Decl;
var ty = new UserDefinedType(e.tok, decl.Name, decl, ri.TypeArgs);
if (ty.AsNewtype != null) {
if (e.Args.Count != 1) {
- Error(e.tok, "conversion operation to {0} got wrong number of arguments (expected 1, got {1})", decl.Name, e.Args.Count);
+ reporter.Error(MessageSource.Resolver, e.tok, "conversion operation to {0} got wrong number of arguments (expected 1, got {1})", decl.Name, e.Args.Count);
}
var conversionArg = 1 <= e.Args.Count ? e.Args[0] :
ty.IsNumericBased(Type.NumericPersuation.Int) ? LiteralExpr.CreateIntLiteral(e.tok, 0) :
@@ -8142,7 +9514,7 @@ namespace Microsoft.Dafny
ResolveExpression(e.Args[i], opts);
}
} else {
- Error(e.tok, "name of type ({0}) is used as a function", decl.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a function", decl.Name);
}
}
} else {
@@ -8152,10 +9524,10 @@ namespace Microsoft.Dafny
var cRhs = new MethodCallInformation(e.tok, mse, e.Args);
return cRhs;
} else {
- Error(e.tok, "method call is not allowed to be used in an expression context ({0})", mse.Member.Name);
+ reporter.Error(MessageSource.Resolver, e.tok, "method call is not allowed to be used in an expression context ({0})", mse.Member.Name);
}
} else if (lhs != null) { // if e.Lhs.Resolved is null, then e.Lhs was not successfully resolved and an error has already been reported
- Error(e.tok, "non-function expression (of type {0}) is called with parameters", e.Lhs.Type);
+ reporter.Error(MessageSource.Resolver, e.tok, "non-function expression (of type {0}) is called with parameters", e.Lhs.Type);
}
}
} else {
@@ -8163,14 +9535,13 @@ namespace Microsoft.Dafny
var callee = mse == null ? null : mse.Member as Function;
if (fnType.Arity != e.Args.Count) {
var what = callee != null ? string.Format("function '{0}'", callee.Name) : string.Format("function type '{0}'", fnType);
- Error(e.tok, "wrong number of arguments to function application ({0} expects {1}, got {2})", what, fnType.Arity, e.Args.Count);
+ reporter.Error(MessageSource.Resolver, e.tok, "wrong number of arguments to function application ({0} expects {1}, got {2})", what, fnType.Arity, e.Args.Count);
} else {
for (var i = 0; i < fnType.Arity; i++) {
- if (!UnifyTypes(fnType.Args[i], e.Args[i].Type)) {
- Error(e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type);
- }
+ ConstrainTypes(fnType.Args[i], e.Args[i].Type,
+ e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type);
}
- if (errorCount != ErrorCount) {
+ if (errorCount != reporter.Count(ErrorLevel.Error)) {
// do nothing else; error has been reported
} else if (callee != null) {
// produce a FunctionCallExpr instead of an ApplyExpr(MemberSelectExpr)
@@ -8194,9 +9565,7 @@ namespace Microsoft.Dafny
ResolveExpression(farg, opts);
Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression
Type s = SubstType(callee.Formals[i].Type, rr.TypeArgumentSubstitutions);
- if (!UnifyTypes(farg.Type, s)) {
- Error(rr, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type);
- }
+ ConstrainTypes(farg.Type, s, rr, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type);
}
rr.Type = SubstType(callee.ResultType, rr.TypeArgumentSubstitutions);
// further bookkeeping
@@ -8237,12 +9606,12 @@ namespace Microsoft.Dafny
DatatypeCtor ctor;
if (!datatypeCtors[dt].TryGetValue(dtv.MemberName, out ctor)) {
- Error(dtv.tok, "undeclared constructor {0} in datatype {1}", dtv.MemberName, dtv.DatatypeName);
+ reporter.Error(MessageSource.Resolver, dtv.tok, "undeclared constructor {0} in datatype {1}", dtv.MemberName, dtv.DatatypeName);
} else {
Contract.Assert(ctor != null); // follows from postcondition of TryGetValue
dtv.Ctor = ctor;
if (ctor.Formals.Count != dtv.Arguments.Count) {
- Error(dtv.tok, "wrong number of arguments to datatype constructor {0} (found {1}, expected {2})", ctor.Name, dtv.Arguments.Count, ctor.Formals.Count);
+ reporter.Error(MessageSource.Resolver, dtv.tok, "wrong number of arguments to datatype constructor {0} (found {1}, expected {2})", ctor.Name, dtv.Arguments.Count, ctor.Formals.Count);
}
}
int j = 0;
@@ -8252,9 +9621,7 @@ namespace Microsoft.Dafny
Contract.Assert(arg.Type != null); // follows from postcondition of ResolveExpression
if (formal != null) {
Type st = SubstType(formal.Type, subst);
- if (!UnifyTypes(arg.Type, st)) {
- Error(arg.tok, "incorrect type of datatype constructor argument (found {0}, expected {1})", arg.Type, st);
- }
+ ConstrainTypes(arg.Type, st, arg.tok, "incorrect type of datatype constructor argument (found {0}, expected {1})", arg.Type, st);
}
j++;
}
@@ -8290,21 +9657,21 @@ namespace Microsoft.Dafny
/// Generate an error for every non-ghost feature used in "expr".
/// Requires "expr" to have been successfully resolved.
/// </summary>
- void CheckIsNonGhost(Expression expr) {
+ void CheckIsCompilable(Expression expr) {
Contract.Requires(expr != null);
Contract.Requires(expr.WasResolved()); // this check approximates the requirement that "expr" be resolved
if (expr is IdentifierExpr) {
var e = (IdentifierExpr)expr;
if (e.Var != null && e.Var.IsGhost) {
- Error(expr, "ghost variables are allowed only in specification contexts");
+ reporter.Error(MessageSource.Resolver, expr, "ghost variables are allowed only in specification contexts");
return;
}
} else if (expr is MemberSelectExpr) {
var e = (MemberSelectExpr)expr;
if (e.Member != null && e.Member.IsGhost) {
- Error(expr, "ghost fields are allowed only in specification contexts");
+ reporter.Error(MessageSource.Resolver, expr, "ghost fields are allowed only in specification contexts");
return;
}
@@ -8312,14 +9679,14 @@ namespace Microsoft.Dafny
var e = (FunctionCallExpr)expr;
if (e.Function != null) {
if (e.Function.IsGhost) {
- Error(expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')");
+ reporter.Error(MessageSource.Resolver, expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')");
return;
}
// function is okay, so check all NON-ghost arguments
- CheckIsNonGhost(e.Receiver);
+ CheckIsCompilable(e.Receiver);
for (int i = 0; i < e.Function.Formals.Count; i++) {
if (!e.Function.Formals[i].IsGhost) {
- CheckIsNonGhost(e.Args[i]);
+ CheckIsCompilable(e.Args[i]);
}
}
}
@@ -8331,26 +9698,26 @@ namespace Microsoft.Dafny
// note that if resolution is successful, then |e.Arguments| == |e.Ctor.Formals|
for (int i = 0; i < e.Arguments.Count; i++) {
if (!e.Ctor.Formals[i].IsGhost) {
- CheckIsNonGhost(e.Arguments[i]);
+ CheckIsCompilable(e.Arguments[i]);
}
}
return;
} else if (expr is OldExpr) {
- Error(expr, "old expressions are allowed only in specification and ghost contexts");
+ reporter.Error(MessageSource.Resolver, expr, "old expressions are allowed only in specification and ghost contexts");
return;
} else if (expr is UnaryOpExpr) {
var e = (UnaryOpExpr)expr;
if (e.Op == UnaryOpExpr.Opcode.Fresh) {
- Error(expr, "fresh expressions are allowed only in specification and ghost contexts");
+ reporter.Error(MessageSource.Resolver, expr, "fresh expressions are allowed only in specification and ghost contexts");
return;
}
} else if (expr is StmtExpr) {
var e = (StmtExpr)expr;
// ignore the statement
- CheckIsNonGhost(e.E);
+ CheckIsCompilable(e.E);
return;
} else if (expr is BinaryExpr) {
@@ -8358,7 +9725,7 @@ namespace Microsoft.Dafny
switch (e.ResolvedOp_PossiblyStillUndetermined) {
case BinaryExpr.ResolvedOpcode.RankGt:
case BinaryExpr.ResolvedOpcode.RankLt:
- Error(expr, "rank comparisons are allowed only in specification and ghost contexts");
+ reporter.Error(MessageSource.Resolver, expr, "rank comparisons are allowed only in specification and ghost contexts");
return;
default:
break;
@@ -8369,7 +9736,7 @@ namespace Microsoft.Dafny
switch (e.Op) {
case TernaryExpr.Opcode.PrefixEqOp:
case TernaryExpr.Opcode.PrefixNeqOp:
- Error(expr, "prefix equalities are allowed only in specification and ghost contexts");
+ reporter.Error(MessageSource.Resolver, expr, "prefix equalities are allowed only in specification and ghost contexts");
return;
default:
break;
@@ -8381,54 +9748,77 @@ namespace Microsoft.Dafny
var i = 0;
foreach (var ee in e.RHSs) {
if (!e.LHSs[i].Vars.All(bv => bv.IsGhost)) {
- CheckIsNonGhost(ee);
+ CheckIsCompilable(ee);
}
i++;
}
- CheckIsNonGhost(e.Body);
+ CheckIsCompilable(e.Body);
} else {
Contract.Assert(e.RHSs.Count == 1);
var lhsVarsAreAllGhost = e.BoundVars.All(bv => bv.IsGhost);
if (!lhsVarsAreAllGhost) {
- CheckIsNonGhost(e.RHSs[0]);
+ CheckIsCompilable(e.RHSs[0]);
+ }
+ CheckIsCompilable(e.Body);
+
+ // fill in bounds for this to-be-compiled let-such-that expression
+ Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully
+ var constraint = e.RHSs[0];
+ List<IVariable> missingBounds;
+ var vars = new List<IVariable>(e.BoundVars);
+ var bestBounds = DiscoverBestBounds_MultipleVars(vars, constraint, true, false, out missingBounds);
+ if (missingBounds.Count != 0) {
+ e.Constraint_MissingBounds = missingBounds;
+ foreach (var bv in e.Constraint_MissingBounds) {
+ reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
+ }
+ } else {
+ e.Constraint_Bounds = bestBounds;
}
- CheckIsNonGhost(e.Body);
}
return;
- } else if (expr is QuantifierExpr) {
- var e = (QuantifierExpr)expr;
- if (e.MissingBounds != null) {
- foreach (var bv in e.MissingBounds) {
- Error(expr, "quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
+ } else if (expr is LambdaExpr) {
+ var e = expr as LambdaExpr;
+ CheckIsCompilable(e.Body);
+ return;
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ var uncompilableBoundVars = e.UncompilableBoundVars();
+ if (uncompilableBoundVars.Count != 0) {
+ string what;
+ if (e is SetComprehension) {
+ what = ((SetComprehension)e).Finite ? "set comprehensions" : "iset comprehensions";
+ } else if (e is MapComprehension) {
+ what = ((MapComprehension)e).Finite ? "map comprehensions" : "imap comprehensions";
+ } else {
+ Contract.Assume(e is QuantifierExpr); // otherwise, unexpected ComprehensionExpr (since LambdaExpr is handled separately above)
+ Contract.Assert(((QuantifierExpr)e).SplitQuantifier == null); // No split quantifiers during resolution
+ what = "quantifiers";
}
- return;
- }
- } else if (expr is MapComprehension) {
- var e = (MapComprehension)expr;
- if (e.MissingBounds != null && !e.Finite) {
- foreach (var bv in e.MissingBounds) {
- Error(expr, "imaps in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name);
+ foreach (var bv in uncompilableBoundVars) {
+ reporter.Error(MessageSource.Resolver, expr, "{0} in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for '{1}'", what, bv.Name);
}
return;
}
+ // don't recurse down any attributes
+ if (e.Range != null) { CheckIsCompilable(e.Range); }
+ CheckIsCompilable(e.Term);
+ return;
+
} else if (expr is NamedExpr) {
- if (!moduleInfo.IsGhost)
- CheckIsNonGhost(((NamedExpr)expr).Body);
+ if (!moduleInfo.IsAbstract)
+ CheckIsCompilable(((NamedExpr)expr).Body);
return;
} else if (expr is ChainingExpression) {
// We don't care about the different operators; we only want the operands, so let's get them directly from
// the chaining expression
var e = (ChainingExpression)expr;
- e.Operands.ForEach(CheckIsNonGhost);
- return;
- } else if (expr is LambdaExpr) {
- var e = expr as LambdaExpr;
- CheckIsNonGhost(e.Body);
+ e.Operands.ForEach(CheckIsCompilable);
return;
}
foreach (var ee in expr.SubExpressions) {
- CheckIsNonGhost(ee);
+ CheckIsCompilable(ee);
}
}
@@ -8444,9 +9834,9 @@ namespace Microsoft.Dafny
if (member == null) {
// error has already been reported by ResolveMember
} else if (member is Method) {
- Error(e, "member {0} in type {1} refers to a method, but only functions can be used in this context", e.Name, cce.NonNull(ctype).Name);
+ reporter.Error(MessageSource.Resolver, e, "member {0} in type {1} refers to a method, but only functions can be used in this context", e.Name, cce.NonNull(ctype).Name);
} else if (!(member is Function)) {
- Error(e, "member {0} in type {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name);
+ reporter.Error(MessageSource.Resolver, e, "member {0} in type {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name);
} else {
Function function = (Function)member;
e.Function = function;
@@ -8454,10 +9844,10 @@ namespace Microsoft.Dafny
((FixpointPredicate)function).Uses.Add(e);
}
if (e.Receiver is StaticReceiverExpr && !function.IsStatic) {
- Error(e, "an instance function must be selected via an object, not just a class name");
+ reporter.Error(MessageSource.Resolver, e, "an instance function must be selected via an object, not just a class name");
}
if (function.Formals.Count != e.Args.Count) {
- Error(e, "wrong number of function arguments (got {0}, expected {1})", e.Args.Count, function.Formals.Count);
+ reporter.Error(MessageSource.Resolver, e, "wrong number of function arguments (got {0}, expected {1})", e.Args.Count, function.Formals.Count);
} else {
Contract.Assert(ctype != null); // follows from postcondition of ResolveMember
if (!function.IsStatic) {
@@ -8469,9 +9859,9 @@ namespace Microsoft.Dafny
// in the event that a static function calls another static function (and note that we need the
// type of the receiver in order to find the method, so we could not have made this check
// earlier).
- Error(e.Receiver, "'this' is not allowed in a 'static' context");
+ reporter.Error(MessageSource.Resolver, e.Receiver, "'this' is not allowed in a 'static' context");
} else if (e.Receiver is StaticReceiverExpr) {
- Error(e.Receiver, "call to instance function requires an instance");
+ reporter.Error(MessageSource.Resolver, e.Receiver, "call to instance function requires an instance");
}
}
// build the type substitution map
@@ -8488,9 +9878,7 @@ namespace Microsoft.Dafny
ResolveExpression(farg, opts);
Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression
Type s = SubstType(function.Formals[i].Type, e.TypeArgumentSubstitutions);
- if (!UnifyTypes(farg.Type, s)) {
- Error(e, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type);
- }
+ ConstrainTypes(farg.Type, s, e, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type);
}
e.Type = SubstType(function.ResultType, e.TypeArgumentSubstitutions);
}
@@ -8538,201 +9926,175 @@ namespace Microsoft.Dafny
}
/// <summary>
- /// For a description, see DiscoverBoundsAux.
+ /// For a list of variables "bvars", returns a list of best bounds for each respective variable. If no bound is found for a variable "v", then the bound for
+ /// "v" in the returned list is set to "null" and "v" is added to "missingBounds".
/// </summary>
- public static List<ComprehensionExpr.BoundedPool> DiscoverBounds<VT>(IToken tok, List<VT> bvars, Expression expr, bool polarity, bool returnAllBounds, List<VT> missingBounds) where VT : IVariable {
- var pairs = DiscoverBoundsAux(tok, bvars, expr, polarity, returnAllBounds, false, missingBounds);
- if (pairs == null) {
- return null;
+ public static List<ComprehensionExpr.BoundedPool> DiscoverBestBounds_MultipleVars<VT>(List<VT> bvars, Expression expr, bool polarity, bool onlyFiniteBounds, out List<VT> missingBounds) where VT : IVariable {
+ foreach (var bv in bvars) {
+ var c = GetImpliedTypeConstraint(bv, bv.Type, null);
+ expr = polarity ? Expression.CreateAnd(c, expr) : Expression.CreateImplies(c, expr);
}
- var bounds = new List<ComprehensionExpr.BoundedPool>();
- foreach (var pr in pairs) {
- Contract.Assert(1 <= pr.Item2.Count);
- bounds.AddRange(pr.Item2);
+ List<ComprehensionExpr.BoundedPool> knownBounds = null;
+ var orgCount = bvars.Count;
+ var bests = new List<ComprehensionExpr.BoundedPool>();
+ bool changed = true;
+ // compute the bounds of the BV until no new information is obtained.
+ while (changed) {
+ changed = false;
+ var all = DiscoverAllBounds_Aux_MultipleVars(bvars, expr, polarity, knownBounds);
+ bests = all.ConvertAll(tup => ComprehensionExpr.BoundedPool.GetBest(tup.Item2, onlyFiniteBounds));
+ // check to see if we found new bounds in this iteration
+ int count = 0;
+ // figure out how many bounds are not determined yet.
+ for (int i = 0; i < bests.Count; i++) {
+ if (bests[i] == null || (bests[i] is ComprehensionExpr.RefBoundedPool)) {
+ count++;
+ }
+ }
+ // if there are bounds that are not determined yet and the number of undetermined bounds
+ // changed, we will need to do another iteration.
+ if (count >0 && count != orgCount) {
+ changed = true;
+ knownBounds = bests;
+ orgCount = count;
+ }
}
- return bounds;
+ missingBounds = new List<VT>();
+ for (var i = 0; i < bvars.Count; i++) {
+ if (bests[i] == null) {
+ missingBounds.Add(bvars[i]);
+ }
+ }
+ return bests;
+ }
+
+ public static List<ComprehensionExpr.BoundedPool> DiscoverAllBounds_SingleVar<VT>(VT v, Expression expr) where VT : IVariable {
+ expr = Expression.CreateAnd(GetImpliedTypeConstraint(v, v.Type, null), expr);
+ return DiscoverAllBounds_Aux_SingleVar(new List<VT> { v }, 0, expr, true, null);
+ }
+
+ private static List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>> DiscoverAllBounds_Aux_MultipleVars<VT>(List<VT> bvars, Expression expr, bool polarity, List<ComprehensionExpr.BoundedPool> knownBounds) where VT : IVariable {
+ Contract.Requires(bvars != null);
+ Contract.Requires(expr != null);
+ var bb = new List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>>();
+ for (var j = 0; j < bvars.Count; j++) {
+ var bounds = DiscoverAllBounds_Aux_SingleVar(bvars, j, expr, polarity, knownBounds);
+ bb.Add(new Tuple<VT, List<ComprehensionExpr.BoundedPool>>(bvars[j], bounds));
+ }
+ return bb;
}
/// <summary>
- /// Tries to find a bounded pool for each of the bound variables "bvars" of "expr". If this process
- /// fails, then "null" is returned and the bound variables for which the process fails are added to "missingBounds".
- /// If "returnAllBounds" is false, then:
- /// -- at most one BoundedPool per variable is returned
- /// -- every IntBoundedPool returned has both a lower and an upper bound
- /// -- no SubSetBoundedPool or SuperSetBoundedPool is returned
- /// If "returnAllBounds" is true, then:
- /// -- a variable may give rise to several BoundedPool's
- /// -- IntBoundedPool bounds may have just one component
- /// -- a non-null return value means that some bound were found for each variable (but, for example, perhaps one
- /// variable only has lower bounds, no upper bounds)
- /// Requires "expr" to be successfully resolved.
- /// If "allowAnyIntegers", then integer variables will always be given a bound, but this bound may be WiggleWaggle if
- /// there is no better bound.
+ /// Returns a list of (possibly partial) bounds for "bvars[j]", each of which can be written without mentioning any variable in "bvars[j..]" that is not bounded.
/// </summary>
- public static List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>> DiscoverBoundsAux<VT>(IToken tok, List<VT> bvars, Expression expr, bool polarity, bool returnAllBounds, bool allowAnyIntegers, List<VT> missingBounds) where VT : IVariable {
- Contract.Requires(tok != null);
+ private static List<ComprehensionExpr.BoundedPool> DiscoverAllBounds_Aux_SingleVar<VT>(List<VT> bvars, int j, Expression expr, bool polarity, List<ComprehensionExpr.BoundedPool> knownBounds) where VT : IVariable {
Contract.Requires(bvars != null);
- Contract.Requires(missingBounds != null);
+ Contract.Requires(0 <= j && j < bvars.Count);
Contract.Requires(expr != null);
- Contract.Requires(expr.Type != null); // a sanity check (but not a complete proof) that "expr" has been resolved
- Contract.Ensures(
- (returnAllBounds && Contract.OldValue(missingBounds.Count) <= missingBounds.Count) ||
- (!returnAllBounds &&
- Contract.Result<List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>>>() != null &&
- Contract.Result<List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>>>().Count == bvars.Count &&
- Contract.OldValue(missingBounds.Count) == missingBounds.Count) ||
- (!returnAllBounds &&
- Contract.Result<List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>>>() == null &&
- Contract.OldValue(missingBounds.Count) < missingBounds.Count));
-
- var allBounds = new List<Tuple<VT, List<ComprehensionExpr.BoundedPool>>>();
- bool foundError = false;
- foreach (var bv in bvars) {
- var c = TypeConstraint(bv, bv.Type);
- expr = polarity ? Expression.CreateAnd(c, expr) : Expression.CreateImplies(c, expr);
- }
- for (int j = 0; j < bvars.Count; j++) {
- var bv = bvars[j];
- var bounds = new List<ComprehensionExpr.BoundedPool>();
- if (bv.Type.IsBoolType) {
- // easy
- bounds.Add(new ComprehensionExpr.BoolBoundedPool());
- } else {
- bool foundBoundsForBv = false;
- if (bv.Type.IsIndDatatype && bv.Type.AsIndDatatype.HasFinitePossibleValues) {
- bounds.Add(new ComprehensionExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype));
- foundBoundsForBv = true;
- }
- // Go through the conjuncts of the range expression to look for bounds.
- Expression lowerBound = null;
- Expression upperBound = null;
- if (returnAllBounds && lowerBound != null) {
- bounds.Add(new ComprehensionExpr.IntBoundedPool(lowerBound, upperBound));
- lowerBound = null;
- foundBoundsForBv = true;
- }
- foreach (var conjunct in NormalizedConjuncts(expr, polarity)) {
- var c = conjunct as BinaryExpr;
- if (c == null) {
- goto CHECK_NEXT_CONJUNCT;
- }
- var e0 = c.E0;
- var e1 = c.E1;
- int whereIsBv = SanitizeForBoundDiscovery(bvars, j, c.ResolvedOp, ref e0, ref e1);
- if (whereIsBv < 0) {
- goto CHECK_NEXT_CONJUNCT;
- }
- switch (c.ResolvedOp) {
- case BinaryExpr.ResolvedOpcode.InSet:
- if (whereIsBv == 0) {
- bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- }
- break;
- case BinaryExpr.ResolvedOpcode.Subset:
- if (returnAllBounds) {
- if (whereIsBv == 0) {
- bounds.Add(new ComprehensionExpr.SubSetBoundedPool(e1));
- } else {
- bounds.Add(new ComprehensionExpr.SuperSetBoundedPool(e0));
- }
- foundBoundsForBv = true;
- }
- break;
- case BinaryExpr.ResolvedOpcode.InMultiSet:
- if (whereIsBv == 0) {
- bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- }
- break;
- case BinaryExpr.ResolvedOpcode.InSeq:
- if (whereIsBv == 0) {
- bounds.Add(new ComprehensionExpr.SeqBoundedPool(e1));
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- }
- break;
- case BinaryExpr.ResolvedOpcode.InMap:
- if (whereIsBv == 0 && e1.Type.AsMapType.Finite) {
- bounds.Add(new ComprehensionExpr.MapBoundedPool(e1));
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- }
- break;
- case BinaryExpr.ResolvedOpcode.EqCommon:
- if (bv.Type is IntType) {
- var otherOperand = whereIsBv == 0 ? e1 : e0;
- bounds.Add(new ComprehensionExpr.IntBoundedPool(otherOperand, Expression.CreateIncrement(otherOperand, 1)));
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- } else if (returnAllBounds && bv.Type is SetType) {
- var otherOperand = whereIsBv == 0 ? e1 : e0;
- bounds.Add(new ComprehensionExpr.SubSetBoundedPool(otherOperand));
- foundBoundsForBv = true;
- }
- break;
- case BinaryExpr.ResolvedOpcode.Gt:
- case BinaryExpr.ResolvedOpcode.Ge:
- Contract.Assert(false); throw new cce.UnreachableException(); // promised by postconditions of NormalizedConjunct
- case BinaryExpr.ResolvedOpcode.Lt:
- if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {
- if (whereIsBv == 0 && upperBound == null) {
- upperBound = e1; // bv < E
- } else if (whereIsBv == 1 && lowerBound == null) {
- lowerBound = Expression.CreateIncrement(e0, 1); // E < bv
- }
- }
- break;
- case BinaryExpr.ResolvedOpcode.Le:
- if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {
- if (whereIsBv == 0 && upperBound == null) {
- upperBound = Expression.CreateIncrement(e1, 1); // bv <= E
- } else if (whereIsBv == 1 && lowerBound == null) {
- lowerBound = e0; // E <= bv
- }
- }
- break;
- default:
- break;
+ var bv = bvars[j];
+ var bounds = new List<ComprehensionExpr.BoundedPool>();
+
+ // Maybe the type itself gives a bound
+ if (bv.Type.IsBoolType) {
+ bounds.Add(new ComprehensionExpr.BoolBoundedPool());
+ } else if (bv.Type.IsCharType) {
+ bounds.Add(new ComprehensionExpr.CharBoundedPool());
+ } else if (bv.Type.IsRefType) {
+ bounds.Add(new ComprehensionExpr.RefBoundedPool(bv.Type));
+ } else if (bv.Type.IsIndDatatype && bv.Type.AsIndDatatype.HasFinitePossibleValues) {
+ bounds.Add(new ComprehensionExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype));
+ } else if (bv.Type.IsNumericBased(Type.NumericPersuation.Int)) {
+ bounds.Add(new AssignSuchThatStmt.WiggleWaggleBound());
+ }
+
+ // Go through the conjuncts of the range expression to look for bounds.
+ foreach (var conjunct in NormalizedConjuncts(expr, polarity)) {
+ var c = conjunct as BinaryExpr;
+ if (c == null) {
+ // We only know what to do with binary expressions
+ continue;
+ }
+ var e0 = c.E0;
+ var e1 = c.E1;
+ int whereIsBv = SanitizeForBoundDiscovery(bvars, j, c.ResolvedOp, knownBounds, ref e0, ref e1);
+ if (whereIsBv < 0) {
+ continue;
+ }
+ switch (c.ResolvedOp) {
+ case BinaryExpr.ResolvedOpcode.InSet:
+ if (whereIsBv == 0 && e1.Type.AsSetType.Finite) {
+ bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
}
- if ((lowerBound != null && upperBound != null) ||
- (returnAllBounds && (lowerBound != null || upperBound != null))) {
- // we have found two halves (or, in the case of returnAllBounds, we have found some bound)
- bounds.Add(new ComprehensionExpr.IntBoundedPool(lowerBound, upperBound));
- lowerBound = null;
- upperBound = null;
- foundBoundsForBv = true;
- if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
- }
- CHECK_NEXT_CONJUNCT: ;
- }
- if (!foundBoundsForBv) {
- // we have checked every conjunct in the range expression and still have not discovered good bounds
- if (allowAnyIntegers && bv.Type is IntType) {
- bounds.Add(new AssignSuchThatStmt.WiggleWaggleBound());
+ break;
+ case BinaryExpr.ResolvedOpcode.Subset:
+ if (whereIsBv == 0) {
+ bounds.Add(new ComprehensionExpr.SubSetBoundedPool(e1));
} else {
- missingBounds.Add(bv); // record failing bound variable
- foundError = true;
+ bounds.Add(new ComprehensionExpr.SuperSetBoundedPool(e0));
}
- }
+ break;
+ case BinaryExpr.ResolvedOpcode.InMultiSet:
+ if (whereIsBv == 0) {
+ bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.InSeq:
+ if (whereIsBv == 0) {
+ bounds.Add(new ComprehensionExpr.SeqBoundedPool(e1));
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.InMap:
+ if (whereIsBv == 0 && e1.Type.AsMapType.Finite) {
+ bounds.Add(new ComprehensionExpr.MapBoundedPool(e1));
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.EqCommon:
+ // TODO: Use the new ComprehensionExpr.ExactBoundedPool
+ if (bv.Type.IsNumericBased(Type.NumericPersuation.Int)) {
+ var otherOperand = whereIsBv == 0 ? e1 : e0;
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(otherOperand, Expression.CreateIncrement(otherOperand, 1)));
+ } else if (bv.Type is SetType) {
+ var otherOperand = whereIsBv == 0 ? e1 : e0;
+ bounds.Add(new ComprehensionExpr.SubSetBoundedPool(otherOperand));
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.Gt:
+ case BinaryExpr.ResolvedOpcode.Ge:
+ Contract.Assert(false); throw new cce.UnreachableException(); // promised by postconditions of NormalizedConjunct
+ case BinaryExpr.ResolvedOpcode.Lt:
+ if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {
+ if (whereIsBv == 0) { // bv < E
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(null, e1));
+ } else { // E < bv
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(Expression.CreateIncrement(e0, 1), null));
+ }
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.Le:
+ if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {
+ if (whereIsBv == 0) { // bv <= E
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(null, Expression.CreateIncrement(e1, 1)));
+ } else { // E <= bv
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(e0, null));
+ }
+ }
+ break;
+ default:
+ break;
}
- CHECK_NEXT_BOUND_VARIABLE: ; // should goto here only if the bound for the current variable has been discovered (otherwise, return with null from this method)
- allBounds.Add(new Tuple<VT, List<ComprehensionExpr.BoundedPool>>(bv, bounds));
}
- return foundError ? null : allBounds;
+ return bounds;
}
- static Expression TypeConstraint(IVariable bv, Type ty) {
+ static Expression GetImpliedTypeConstraint(IVariable bv, Type ty, ErrorReporter reporter) {
Contract.Requires(bv != null);
Contract.Requires(ty != null);
ty = ty.NormalizeExpand();
var dd = ty.AsNewtype;
if (dd != null) {
- var c = TypeConstraint(bv, dd.BaseType);
+ var c = GetImpliedTypeConstraint(bv, dd.BaseType, reporter);
if (dd.Var != null) {
- c = Expression.CreateAnd(c, new Translator().Substitute(dd.Constraint, dd.Var, Expression.CreateIdentExpr(bv)));
+ c = Expression.CreateAnd(c, new Translator(reporter).Substitute(dd.Constraint, dd.Var, Expression.CreateIdentExpr(bv)));
}
return c;
}
@@ -8750,7 +10112,7 @@ namespace Microsoft.Dafny
/// The other of "e0" and "e1" is an expression whose free variables are not among "boundVars[bvi..]".
/// Ensures that the resulting "e0" and "e1" are not ConcreteSyntaxExpression's.
/// </summary>
- static int SanitizeForBoundDiscovery<VT>(List<VT> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, ref Expression e0, ref Expression e1) where VT : IVariable {
+ static int SanitizeForBoundDiscovery<VT>(List<VT> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, List<ComprehensionExpr.BoundedPool> knownBounds, ref Expression e0, ref Expression e1) where VT : IVariable {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
Contract.Requires(boundVars != null);
@@ -8845,10 +10207,10 @@ namespace Microsoft.Dafny
}
// Finally, check that the other side does not contain "bv" or any of the bound variables
- // listed after "bv" in the quantifier.
+ // listed after "bv" in the quantifier that is not bounded.
var fv = FreeVariables(thatSide);
for (int i = bvi; i < boundVars.Count; i++) {
- if (fv.Contains(boundVars[i])) {
+ if (fv.Contains(boundVars[i]) && (knownBounds == null || knownBounds[i] == null)) {
return -1;
}
}
@@ -8998,6 +10360,8 @@ namespace Microsoft.Dafny
} else if (expr is QuantifierExpr) {
var e = (QuantifierExpr)expr;
+ Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution
+
var s = FreeVariables(e.LogicalBody());
foreach (var bv in e.BoundVars) {
s.Remove(bv);
@@ -9009,8 +10373,10 @@ namespace Microsoft.Dafny
var s = FreeVariables(e.Source);
foreach (MatchCaseExpr mc in e.Cases) {
var t = FreeVariables(mc.Body);
- foreach (var bv in mc.Arguments) {
- t.Remove(bv);
+ foreach (var cp in mc.CasePatterns) {
+ foreach (var bv in cp.Vars) {
+ t.Remove(bv);
+ }
}
s.UnionWith(t);
}
@@ -9073,39 +10439,32 @@ namespace Microsoft.Dafny
Type argType = new InferredTypeProxy();
IndexableTypeProxy expectedType = new IndexableTypeProxy(domainType, elementType, argType, true, true, true);
- if (!UnifyTypes(e.Seq.Type, expectedType)) {
- Error(e, "sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got {0})", e.Seq.Type);
+ if (!ConstrainTypes(e.Seq.Type, expectedType, e, "sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got {0})", e.Seq.Type)) {
seqErr = true;
}
if (!e.SelectOne) // require sequence or array
{
if (!allowNonUnitArraySelection) {
// require seq
- if (!UnifyTypes(expectedType, new SeqType(new InferredTypeProxy()))) {
- Error(e, "selection requires a sequence (got {0})", e.Seq.Type);
- }
+ ConstrainTypes(expectedType, new SeqType(new InferredTypeProxy()), e, "selection requires a sequence (got {0})", e.Seq.Type);
} else {
if (UnifyTypes(expectedType, new MapType(true, new InferredTypeProxy(), new InferredTypeProxy()))) {
- Error(e, "cannot multiselect a map (got {0} as map type)", e.Seq.Type);
+ reporter.Error(MessageSource.Resolver, e, "cannot multiselect a map (got {0} as map type)", e.Seq.Type);
} else if (UnifyTypes(expectedType, new MapType(false, new InferredTypeProxy(), new InferredTypeProxy()))) {
- Error(e, "cannot multiselect an imap (got {0} as imap type)", e.Seq.Type);
+ reporter.Error(MessageSource.Resolver, e, "cannot multiselect an imap (got {0} as imap type)", e.Seq.Type);
}
}
}
if (e.E0 != null) {
ResolveExpression(e.E0, opts);
Contract.Assert(e.E0.Type != null); // follows from postcondition of ResolveExpression
- if (!UnifyTypes(e.E0.Type, domainType)) {
- Error(e.E0, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E0.Type, domainType);
- }
+ ConstrainTypes(e.E0.Type, domainType, e.E0, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E0.Type, domainType);
}
if (e.E1 != null) {
ResolveExpression(e.E1, opts);
Contract.Assert(e.E1.Type != null); // follows from postcondition of ResolveExpression
- var domType = e.E0 == null ? domainType : new OperationTypeProxy(true, false, false, false, false); // reuse 'domainType' if .E0 did not use it; otherwise, create a new proxy to allow .E1 to be any integer-based numeric type, independent of the integer-based numeric type used by .E0
- if (!UnifyTypes(e.E1.Type, domType)) {
- Error(e.E1, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E1.Type, domType);
- }
+ var domType = e.E0 == null ? domainType : new OperationTypeProxy(true, false, false, false, false, false); // reuse 'domainType' if .E0 did not use it; otherwise, create a new proxy to allow .E1 to be any integer-based numeric type, independent of the integer-based numeric type used by .E0
+ ConstrainTypes(e.E1.Type, domType, e.E1, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E1.Type, domType);
}
if (!seqErr) {
if (e.SelectOne) {
@@ -9281,8 +10640,15 @@ namespace Microsoft.Dafny
IdentifierExpr e = (IdentifierExpr)expr;
return cce.NonNull(e.Var).IsGhost;
} else if (expr is DatatypeValue) {
- DatatypeValue dtv = (DatatypeValue)expr;
- return dtv.Arguments.Exists(arg => UsesSpecFeatures(arg));
+ var e = (DatatypeValue)expr;
+ // check all NON-ghost arguments
+ // note that if resolution is successful, then |e.Arguments| == |e.Ctor.Formals|
+ for (int i = 0; i < e.Arguments.Count; i++) {
+ if (!e.Ctor.Formals[i].IsGhost && UsesSpecFeatures(e.Arguments[i])) {
+ return true;
+ }
+ }
+ return false;
} else if (expr is DisplayExpression) {
DisplayExpression e = (DisplayExpression)expr;
return e.Elements.Exists(ee => UsesSpecFeatures(ee));
@@ -9296,7 +10662,7 @@ namespace Microsoft.Dafny
} else {
return false;
}
- } else if (expr is SeqSelectExpr) {
+ } else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
return UsesSpecFeatures(e.Seq) ||
(e.E0 != null && UsesSpecFeatures(e.E0)) ||
@@ -9310,11 +10676,20 @@ namespace Microsoft.Dafny
UsesSpecFeatures(e.Index) ||
UsesSpecFeatures(e.Value);
} else if (expr is FunctionCallExpr) {
- FunctionCallExpr e = (FunctionCallExpr)expr;
- if (cce.NonNull(e.Function).IsGhost) {
+ var e = (FunctionCallExpr)expr;
+ if (e.Function.IsGhost) {
return true;
}
- return e.Args.Exists(arg => UsesSpecFeatures(arg));
+ // check all NON-ghost arguments
+ if (UsesSpecFeatures(e.Receiver)) {
+ return true;
+ }
+ for (int i = 0; i < e.Function.Formals.Count; i++) {
+ if (!e.Function.Formals[i].IsGhost && UsesSpecFeatures(e.Args[i])) {
+ return true;
+ }
+ }
+ return false;
} else if (expr is ApplyExpr) {
ApplyExpr e = (ApplyExpr)expr;
return UsesSpecFeatures(e.Function) || e.Args.Exists(UsesSpecFeatures);
@@ -9355,20 +10730,20 @@ namespace Microsoft.Dafny
return true; // let-such-that is always ghost
}
} else if (expr is NamedExpr) {
- return moduleInfo.IsGhost ? false : UsesSpecFeatures(((NamedExpr)expr).Body);
- } else if (expr is ComprehensionExpr) {
- if (expr is QuantifierExpr && ((QuantifierExpr)expr).Bounds == null) {
- return true; // the quantifier cannot be compiled if the resolver found no bounds
- }
- return Contract.Exists(expr.SubExpressions, se => UsesSpecFeatures(se));
+ return moduleInfo.IsAbstract ? false : UsesSpecFeatures(((NamedExpr)expr).Body);
+ } else if (expr is QuantifierExpr) {
+ var e = (QuantifierExpr)expr;
+ Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution
+ return e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.LogicalBody());
} else if (expr is SetComprehension) {
var e = (SetComprehension)expr;
- return (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term));
+ return !e.Finite || e.UncompilableBoundVars().Count != 0 || (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term));
} else if (expr is MapComprehension) {
var e = (MapComprehension)expr;
- return (UsesSpecFeatures(e.Range)) || (UsesSpecFeatures(e.Term));
+ return !e.Finite || e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.Range) || UsesSpecFeatures(e.Term);
} else if (expr is LambdaExpr) {
- return Contract.Exists(expr.SubExpressions, UsesSpecFeatures);
+ var e = (LambdaExpr)expr;
+ return UsesSpecFeatures(e.Term);
} else if (expr is WildcardExpr) {
return false;
} else if (expr is StmtExpr) {
@@ -9588,7 +10963,7 @@ namespace Microsoft.Dafny
// this call is disqualified from being a co-call, because it has a postcondition
// (a postcondition could be allowed, as long as it does not get to be used with
// co-recursive calls, because that could be unsound; for example, consider
- // "ensures false;")
+ // "ensures false")
if (!dealsWithCodatatypes) {
e.CoCall = FunctionCallExpr.CoCallResolution.No;
} else {
@@ -9665,17 +11040,27 @@ namespace Microsoft.Dafny
}
}
- // Pushes name-->thing association and returns "true", if name has not already been pushed since the last marker.
- // If name already has been pushed since the last marker, does nothing and returns "false".
- public bool Push(string name, Thing thing) {
+ public enum PushResult { Duplicate, Shadow, Success }
+
+ /// <summary>
+ /// Pushes name-->thing association and returns "Success", if name has not already been pushed since the last marker.
+ /// If name already has been pushed since the last marker, does nothing and returns "Duplicate".
+ /// If the appropriate command-line option is supplied, then this method will also check if "name" shadows a previous
+ /// name; if it does, then it will return "Shadow" instead of "Success".
+ /// </summary>
+ public PushResult Push(string name, Thing thing) {
Contract.Requires(name != null);
Contract.Requires(thing != null);
if (Find(name, true) != null) {
- return false;
+ return PushResult.Duplicate;
} else {
+ var r = PushResult.Success;
+ if (DafnyOptions.O.WarnShadowing && Find(name, false) != null) {
+ r = PushResult.Shadow;
+ }
names.Add(name);
things.Add(thing);
- return true;
+ return r;
}
}
@@ -9700,6 +11085,11 @@ namespace Microsoft.Dafny
return Find(name, false);
}
+ public Thing FindInCurrentScope(string name) {
+ Contract.Requires(name != null);
+ return Find(name, true);
+ }
+
public bool ContainsDecl(Thing t) {
return things.Exists(thing => thing == t);
}
diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs
index 72649b5f..2e18c4e6 100644
--- a/Source/Dafny/Rewriter.cs
+++ b/Source/Dafny/Rewriter.cs
@@ -2,27 +2,29 @@
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Bpl = Microsoft.Boogie;
+using IToken = Microsoft.Boogie.IToken;
namespace Microsoft.Dafny
{
- [ContractClass(typeof(IRewriterContracts))]
- public interface IRewriter
+ public abstract class IRewriter
{
- void PreResolve(ModuleDefinition m);
- void PostResolve(ModuleDefinition m);
- // After SCC/Cyclicity/Recursivity analysis:
- void PostCyclicityResolve(ModuleDefinition m);
- }
- [ContractClassFor(typeof(IRewriter))]
- abstract class IRewriterContracts : IRewriter
- {
- public void PreResolve(ModuleDefinition m) {
+ protected readonly ErrorReporter reporter;
+
+ public IRewriter(ErrorReporter reporter) {
+ Contract.Requires(reporter != null);
+ this.reporter = reporter;
+ }
+
+ internal virtual void PreResolve(ModuleDefinition m) {
Contract.Requires(m != null);
}
- public void PostResolve(ModuleDefinition m) {
+
+ internal virtual void PostResolve(ModuleDefinition m) {
Contract.Requires(m != null);
}
- public void PostCyclicityResolve(ModuleDefinition m) {
+
+ // After SCC/Cyclicity/Recursivity analysis:
+ internal virtual void PostCyclicityResolve(ModuleDefinition m) {
Contract.Requires(m != null);
}
}
@@ -36,6 +38,312 @@ namespace Microsoft.Dafny
}
}
+ public class TriggerGeneratingRewriter : IRewriter {
+ internal TriggerGeneratingRewriter(ErrorReporter reporter) : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PostCyclicityResolve(ModuleDefinition m) {
+ var finder = new Triggers.QuantifierCollector(reporter);
+
+ foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {
+ finder.Visit(decl, false);
+ }
+
+ var triggersCollector = new Triggers.TriggersCollector(finder.exprsInOldContext);
+ foreach (var quantifierCollection in finder.quantifierCollections) {
+ quantifierCollection.ComputeTriggers(triggersCollector);
+ quantifierCollection.CommitTriggers();
+ }
+ }
+ }
+
+ internal class QuantifierSplittingRewriter : IRewriter {
+ internal QuantifierSplittingRewriter(ErrorReporter reporter) : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PostResolve(ModuleDefinition m) {
+ var splitter = new Triggers.QuantifierSplitter();
+ foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {
+ splitter.Visit(decl);
+ }
+ splitter.Commit();
+ }
+ }
+
+ // write out the quantifier for ForallStmt
+ public class ForallStmtRewriter : IRewriter
+ {
+ public ForallStmtRewriter(ErrorReporter reporter) : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PostResolve(ModuleDefinition m) {
+ var forallvisiter = new ForAllStmtVisitor();
+ foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {
+ forallvisiter.Visit(decl, true);
+ }
+ }
+
+ internal class ForAllStmtVisitor : TopDownVisitor<bool>
+ {
+ protected override bool VisitOneStmt(Statement stmt, ref bool st) {
+ if (stmt is ForallStmt) {
+ ForallStmt s = (ForallStmt)stmt;
+ if (s.Kind == ForallStmt.ParBodyKind.Proof) {
+ Expression term = s.Ens.Count != 0 ? s.Ens[0].E : new LiteralExpr(s.Tok, true);
+ for (int i = 1; i < s.Ens.Count; i++) {
+ term = new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.And, term, s.Ens[i].E);
+ }
+ List<Expression> exprList = new List<Expression>();
+ ForallExpr expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, term, s.Attributes);
+ expr.Type = Type.Bool; // resolve here
+ exprList.Add(expr);
+ s.ForallExpressions = exprList;
+ } else if (s.Kind == ForallStmt.ParBodyKind.Assign) {
+ if (s.BoundVars.Count != 0) {
+ var s0 = (AssignStmt)s.S0;
+ if (s0.Rhs is ExprRhs) {
+ List<Expression> exprList = new List<Expression>();
+ Expression Fi = null;
+ Func<Expression, Expression> lhsBuilder = null;
+ var lhs = s0.Lhs.Resolved;
+ var i = s.BoundVars[0];
+ if (s.BoundVars.Count == 1) {
+ //var lhsContext = null;
+ // Detect the following cases:
+ // 0: forall i | R(i) { F(i).f := E(i); }
+ // 1: forall i | R(i) { A[F(i)] := E(i); }
+ // 2: forall i | R(i) { F(i)[N] := E(i); }
+ if (lhs is MemberSelectExpr) {
+ var ll = (MemberSelectExpr)lhs;
+ Fi = ll.Obj;
+ lhsBuilder = e => { var l = new MemberSelectExpr(ll.tok, e, ll.MemberName); l.Member = ll.Member; l.Type = ll.Type; return l; };
+ } else if (lhs is SeqSelectExpr) {
+ var ll = (SeqSelectExpr)lhs;
+ Contract.Assert(ll.SelectOne);
+ if (!Translator.ContainsFreeVariable(ll.Seq, false, i)) {
+ Fi = ll.E0;
+ lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, ll.Seq, e, null); l.Type = ll.Type; return l; };
+ } else if (!Translator.ContainsFreeVariable(ll.E0, false, i)) {
+ Fi = ll.Seq;
+ lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, e, ll.E0, null); l.Type = ll.Type; return l; };
+ }
+ }
+ }
+ var rhs = ((ExprRhs)s0.Rhs).Expr;
+ bool usedInversion = false;
+ if (Fi != null) {
+ var j = new BoundVar(i.tok, i.Name + "#inv", Fi.Type);
+ var jj = Expression.CreateIdentExpr(j);
+ var jList = new List<BoundVar>() { j };
+ var vals = InvertExpression(i, j, s.Range, Fi);
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: Trying to invert:");
+ Console.WriteLine("DEBUG: " + Printer.ExprToString(s.Range) + " && " + j.Name + " == " + Printer.ExprToString(Fi));
+ if (vals == null) {
+ Console.WriteLine("DEBUG: Can't");
+ } else {
+ Console.WriteLine("DEBUG: The inverse is the disjunction of the following:");
+ foreach (var val in vals) {
+ Console.WriteLine("DEBUG: " + Printer.ExprToString(val.Range) + " && " + Printer.ExprToString(val.FInverse) + " == " + i.Name);
+ }
+ }
+#endif
+ if (vals != null) {
+ foreach (var val in vals) {
+ lhs = lhsBuilder(jj);
+ Attributes attributes = new Attributes("trigger", new List<Expression>() { lhs }, s.Attributes);
+ var expr = new ForallExpr(s.Tok, jList, val.Range, new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.EqCommon, lhs, Substitute(rhs, i, val.FInverse)), attributes);
+ expr.Type = Type.Bool; //resolve here
+ exprList.Add(expr);
+ }
+ usedInversion = true;
+ }
+ }
+ if (!usedInversion) {
+ var expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.EqCommon, lhs, rhs), s.Attributes);
+ expr.Type = Type.Bool; // resolve here
+ exprList.Add(expr);
+ }
+ s.ForallExpressions = exprList;
+ }
+ }
+ } else if (s.Kind == ForallStmt.ParBodyKind.Call) {
+ var s0 = (CallStmt)s.S0;
+ Expression term = s0.Method.Ens.Count != 0 ? s0.Method.Ens[0].E : new LiteralExpr(s.Tok, true);
+ for (int i = 1; i < s0.Method.Ens.Count; i++) {
+ term = new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.And, term, s0.Method.Ens[i].E);
+ }
+ List<Expression> exprList = new List<Expression>();
+ ForallExpr expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, term, s.Attributes);
+ expr.Type = Type.Bool; // resolve here
+ exprList.Add(expr);
+ } else {
+ Contract.Assert(false); // unexpected kind
+ }
+ }
+ return true; //visit the sub-parts with the same "st"
+ }
+
+ internal class ForallStmtTranslationValues
+ {
+ public readonly Expression Range;
+ public readonly Expression FInverse;
+ public ForallStmtTranslationValues(Expression range, Expression fInverse) {
+ Contract.Requires(range != null);
+ Contract.Requires(fInverse != null);
+ Range = range;
+ FInverse = fInverse;
+ }
+ public ForallStmtTranslationValues Subst(IVariable j, Expression e) {
+ Contract.Requires(j != null);
+ Contract.Requires(e != null);
+ Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter, Type>();
+ var substMap = new Dictionary<IVariable, Expression>();
+ substMap.Add(j, e);
+ Translator.Substituter sub = new Translator.Substituter(null, substMap, typeMap, null);
+ var v = new ForallStmtTranslationValues(sub.Substitute(Range), sub.Substitute(FInverse));
+ return v;
+ }
+ }
+
+ /// <summary>
+ /// Find piecewise inverse of F under R. More precisely, find lists of expressions P and F-1
+ /// such that
+ /// R(i) && j == F(i)
+ /// holds iff the disjunction of the following predicates holds:
+ /// P_0(j) && F-1_0(j) == i
+ /// ...
+ /// P_{n-1}(j) && F-1_{n-1}(j) == i
+ /// If no such disjunction is found, return null.
+ /// If such a disjunction is found, return for each disjunct:
+ /// * The predicate P_k(j), which is an expression that may have free occurrences of j (but no free occurrences of i)
+ /// * The expression F-1_k(j), which also may have free occurrences of j but not of i
+ /// </summary>
+ private List<ForallStmtTranslationValues> InvertExpression(BoundVar i, BoundVar j, Expression R, Expression F) {
+ Contract.Requires(i != null);
+ Contract.Requires(j != null);
+ Contract.Requires(R != null);
+ Contract.Requires(F != null);
+ var vals = new List<ForallStmtTranslationValues>(InvertExpressionIter(i, j, R, F));
+ if (vals.Count == 0) {
+ return null;
+ } else {
+ return vals;
+ }
+ }
+ /// <summary>
+ /// See InvertExpression.
+ /// </summary>
+ private IEnumerable<ForallStmtTranslationValues> InvertExpressionIter(BoundVar i, BoundVar j, Expression R, Expression F) {
+ Contract.Requires(i != null);
+ Contract.Requires(j != null);
+ Contract.Requires(R != null);
+ Contract.Requires(F != null);
+ F = F.Resolved;
+ if (!Translator.ContainsFreeVariable(F, false, i)) {
+ // We're looking at R(i) && j == K.
+ // We cannot invert j == K, but if we're lucky, R(i) contains a conjunct i==G.
+ Expression r = Expression.CreateBoolLiteral(R.tok, true);
+ Expression G = null;
+ foreach (var c in Expression.Conjuncts(R)) {
+ if (G == null && c is BinaryExpr) {
+ var bin = (BinaryExpr)c;
+ if (BinaryExpr.IsEqualityOp(bin.ResolvedOp)) {
+ var id = bin.E0.Resolved as IdentifierExpr;
+ if (id != null && id.Var == i) {
+ G = bin.E1;
+ continue;
+ }
+ id = bin.E1.Resolved as IdentifierExpr;
+ if (id != null && id.Var == i) {
+ G = bin.E0;
+ continue;
+ }
+ }
+ }
+ r = Expression.CreateAnd(r, c);
+ }
+ if (G != null) {
+ var jIsK = Expression.CreateEq(Expression.CreateIdentExpr(j), F, j.Type);
+ var rr = Substitute(r, i, G);
+ yield return new ForallStmtTranslationValues(Expression.CreateAnd(rr, jIsK), G);
+ }
+ } else if (F is IdentifierExpr) {
+ var e = (IdentifierExpr)F;
+ if (e.Var == i) {
+ // We're looking at R(i) && j == i, which is particularly easy to invert: R(j) && j == i
+ var jj = Expression.CreateIdentExpr(j);
+ yield return new ForallStmtTranslationValues(Substitute(R, i, jj), jj);
+ }
+ } else if (F is BinaryExpr) {
+ var bin = (BinaryExpr)F;
+ if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {
+ if (!Translator.ContainsFreeVariable(bin.E1, false, i)) {
+ // We're looking at: R(i) && j == f(i) + K.
+ // By a recursive call, we'll ask to invert: R(i) && j' == f(i).
+ // For each P_0(j') && f-1_0(j') == i we get back, we yield:
+ // P_0(j - K) && f-1_0(j - K) == i
+ var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E1);
+ foreach (var val in InvertExpression(i, j, R, bin.E0)) {
+ yield return val.Subst(j, jMinusK);
+ }
+ } else if (!Translator.ContainsFreeVariable(bin.E0, false, i)) {
+ // We're looking at: R(i) && j == K + f(i)
+ // Do as in previous case, but with operands reversed.
+ var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E0);
+ foreach (var val in InvertExpression(i, j, R, bin.E1)) {
+ yield return val.Subst(j, jMinusK);
+ }
+ }
+ } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {
+ if (!Translator.ContainsFreeVariable(bin.E1, false, i)) {
+ // We're looking at: R(i) && j == f(i) - K
+ // Recurse on f(i) and then replace j := j + K
+ var jPlusK = Expression.CreateAdd(Expression.CreateIdentExpr(j), bin.E1);
+ foreach (var val in InvertExpression(i, j, R, bin.E0)) {
+ yield return val.Subst(j, jPlusK);
+ }
+ } else if (!Translator.ContainsFreeVariable(bin.E0, false, i)) {
+ // We're looking at: R(i) && j == K - f(i)
+ // Recurse on f(i) and then replace j := K - j
+ var kMinusJ = Expression.CreateAdd(Expression.CreateIdentExpr(j), bin.E0);
+ foreach (var val in InvertExpression(i, j, R, bin.E1)) {
+ yield return val.Subst(j, kMinusJ);
+ }
+ }
+ }
+ } else if (F is ITEExpr) {
+ var ife = (ITEExpr)F;
+ // We're looking at R(i) && j == if A(i) then B(i) else C(i), which is equivalent to the disjunction of:
+ // R(i) && A(i) && j == B(i)
+ // R(i) && !A(i) && j == C(i)
+ // We recurse on each one, yielding the results
+ var r = Expression.CreateAnd(R, ife.Test);
+ var valsThen = InvertExpression(i, j, r, ife.Thn);
+ if (valsThen != null) {
+ r = Expression.CreateAnd(R, Expression.CreateNot(ife.tok, ife.Test));
+ var valsElse = InvertExpression(i, j, r, ife.Els);
+ if (valsElse != null) {
+ foreach (var val in valsThen) { yield return val; }
+ foreach (var val in valsElse) { yield return val; }
+ }
+ }
+ }
+ }
+
+ Expression Substitute(Expression expr, IVariable v, Expression e) {
+ Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();
+ Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter, Type>();
+ substMap.Add(v, e);
+ Translator.Substituter sub = new Translator.Substituter(null, substMap, typeMap, null);
+ return sub.Substitute(expr);
+ }
+ }
+ }
+
/// <summary>
/// AutoContracts is an experimental feature that will fill much of the dynamic-frames boilerplate
/// into a class. From the user's perspective, what needs to be done is simply:
@@ -45,10 +353,10 @@ namespace Microsoft.Dafny
/// AutoContracts will then:
///
/// Declare:
- /// ghost var Repr: set(object);
+ /// ghost var Repr: set(object)
///
/// For function/predicate Valid(), insert:
- /// reads this, Repr;
+ /// reads this, Repr
/// Into body of Valid(), insert (at the beginning of the body):
/// this in Repr && null !in Repr
/// and also insert, for every array-valued field A declared in the class:
@@ -60,23 +368,32 @@ namespace Microsoft.Dafny
///
/// For every constructor, add:
/// modifies this;
- /// ensures Valid() && fresh(Repr - {this});
+ /// ensures Valid() && fresh(Repr - {this})
/// At the end of the body of the constructor, add:
/// Repr := {this};
/// if (A != null) { Repr := Repr + {A}; }
/// if (F != null) { Repr := Repr + {F} + F.Repr; }
///
- /// For every method, add:
- /// requires Valid();
- /// modifies Repr;
- /// ensures Valid() && fresh(Repr - old(Repr));
+ /// For every non-static non-ghost method that is not a "simple query method",
+ /// add:
+ /// requires Valid()
+ /// modifies Repr
+ /// ensures Valid() && fresh(Repr - old(Repr))
/// At the end of the body of the method, add:
/// if (A != null) { Repr := Repr + {A}; }
/// if (F != null) { Repr := Repr + {F} + F.Repr; }
+ /// For every non-static method that is either ghost or is a "simple query method",
+ /// add:
+ /// requires Valid()
/// </summary>
public class AutoContractsRewriter : IRewriter
{
- public void PreResolve(ModuleDefinition m) {
+ public AutoContractsRewriter(ErrorReporter reporter)
+ : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PreResolve(ModuleDefinition m) {
foreach (var d in m.TopLevelDecls) {
bool sayYes = true;
if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) {
@@ -89,7 +406,7 @@ namespace Microsoft.Dafny
// Add: ghost var Repr: set<object>;
// ...unless a field with that name is already present
if (!cl.Members.Exists(member => member is Field && member.Name == "Repr")) {
- Type ty = new SetType(new ObjectType());
+ Type ty = new SetType(true, new ObjectType());
cl.Members.Add(new Field(new AutoGeneratedToken(cl.tok), "Repr", true, ty, null));
}
@@ -119,7 +436,7 @@ namespace Microsoft.Dafny
// ensures fresh(Repr - {this});
var freshness = new UnaryOpExpr(tok, UnaryOpExpr.Opcode.Fresh, new BinaryExpr(tok, BinaryExpr.Opcode.Sub,
new MemberSelectExpr(tok, new ImplicitThisExpr(tok), "Repr"),
- new SetDisplayExpr(tok, new List<Expression>() { new ThisExpr(tok) })));
+ new SetDisplayExpr(tok, true, new List<Expression>() { new ThisExpr(tok) })));
ctor.Ens.Insert(1, new MaybeFreeExpression(freshness));
} else if (member is Method && !member.IsStatic) {
var m = (Method)member;
@@ -132,7 +449,7 @@ namespace Microsoft.Dafny
}
}
- public void PostResolve(ModuleDefinition m) {
+ internal override void PostResolve(ModuleDefinition m) {
foreach (var d in m.TopLevelDecls) {
bool sayYes = true;
if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) {
@@ -141,9 +458,6 @@ namespace Microsoft.Dafny
}
}
- public void PostCyclicityResolve(ModuleDefinition m) {
- }
-
void ProcessClassPostResolve(ClassDecl cl) {
// Find all fields of a reference type, and make a note of whether or not the reference type has a Repr field.
// Also, find the Repr field and the function Valid in class "cl"
@@ -246,8 +560,8 @@ namespace Microsoft.Dafny
if (ctor.Body != null) {
var bodyStatements = ((BlockStmt)ctor.Body).Body;
// Repr := {this};
- var e = new SetDisplayExpr(tok, new List<Expression>() { self });
- e.Type = new SetType(new ObjectType());
+ var e = new SetDisplayExpr(tok, true, new List<Expression>() { self });
+ e.Type = new SetType(true, new ObjectType());
Statement s = new AssignStmt(tok, tok, Repr, new ExprRhs(e));
s.IsGhost = true;
bodyStatements.Add(s);
@@ -255,7 +569,7 @@ namespace Microsoft.Dafny
AddSubobjectReprs(tok, subobjects, bodyStatements, self, implicitSelf, cNull, Repr);
}
- } else if (member is Method && !member.IsStatic) {
+ } else if (member is Method && !member.IsStatic && !member.IsGhost) {
var m = (Method)member;
if (Valid != null && !IsSimpleQueryMethod(m)) {
if (member.RefinementBase == null) {
@@ -297,8 +611,8 @@ namespace Microsoft.Dafny
foreach (var ff in subobjects) {
var F = Resolver.NewMemberSelectExpr(tok, implicitSelf, ff.Item1, null); // create a resolved MemberSelectExpr
- Expression e = new SetDisplayExpr(tok, new List<Expression>() { F });
- e.Type = new SetType(new ObjectType()); // resolve here
+ Expression e = new SetDisplayExpr(tok, true, new List<Expression>() { F });
+ e.Type = new SetType(true, new ObjectType()); // resolve here
var rhs = new BinaryExpr(tok, BinaryExpr.Opcode.Add, Repr, e);
rhs.ResolvedOp = BinaryExpr.ResolvedOpcode.Union; // resolve here
rhs.Type = Repr.Type; // resolve here
@@ -318,7 +632,7 @@ namespace Microsoft.Dafny
e = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NeqCommon, F, cNull);
var thn = new BlockStmt(tok, tok, new List<Statement>() { s });
thn.IsGhost = true;
- s = new IfStmt(tok, tok, e, thn, null);
+ s = new IfStmt(tok, tok, false, e, thn, null);
s.IsGhost = true;
// finally, add s to the body
bodyStatements.Add(s);
@@ -386,20 +700,20 @@ namespace Microsoft.Dafny
/// specifically asks to see it via the reveal_foo() lemma
/// </summary>
public class OpaqueFunctionRewriter : IRewriter {
- readonly ResolutionErrorReporter reporter;
protected Dictionary<Function, Function> fullVersion; // Given an opaque function, retrieve the full
protected Dictionary<Function, Function> original; // Given a full version of an opaque function, find the original opaque version
protected Dictionary<Lemma, Function> revealOriginal; // Map reveal_* lemmas back to their original functions
- public OpaqueFunctionRewriter(ResolutionErrorReporter reporter)
- : base() {
- this.reporter = reporter;
+ public OpaqueFunctionRewriter(ErrorReporter reporter)
+ : base(reporter) {
+ Contract.Requires(reporter != null);
+
fullVersion = new Dictionary<Function, Function>();
original = new Dictionary<Function, Function>();
revealOriginal = new Dictionary<Lemma, Function>();
}
- public void PreResolve(ModuleDefinition m) {
+ internal override void PreResolve(ModuleDefinition m) {
foreach (var d in m.TopLevelDecls) {
if (d is ClassDecl) {
DuplicateOpaqueClassFunctions((ClassDecl)d);
@@ -407,7 +721,7 @@ namespace Microsoft.Dafny
}
}
- public void PostResolve(ModuleDefinition m) {
+ internal override void PostResolve(ModuleDefinition m) {
// Fix up the ensures clause of the full version of the function,
// since it may refer to the original opaque function
foreach (var fn in ModuleDefinition.AllFunctions(m.TopLevelDecls)) {
@@ -432,7 +746,7 @@ namespace Microsoft.Dafny
}
}
- public void PostCyclicityResolve(ModuleDefinition m) {
+ internal override void PostCyclicityResolve(ModuleDefinition m) {
// Add layer quantifier if the function is recursive
foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {
if (decl is Lemma) {
@@ -477,7 +791,7 @@ namespace Microsoft.Dafny
if (!Attributes.Contains(f.Attributes, "opaque")) {
// Nothing to do
} else if (f.IsProtected) {
- reporter.Error(f.tok, ":opaque is not allowed to be applied to protected functions (this will be allowed when the language introduces 'opaque'/'reveal' as keywords)");
+ reporter.Error(MessageSource.Rewriter, f.tok, ":opaque is not allowed to be applied to protected functions (this will be allowed when the language introduces 'opaque'/'reveal' as keywords)");
} else if (!RefinementToken.IsInherited(f.tok, c.Module)) {
// Create a copy, which will be the internal version with a full body
// which will allow us to verify that the ensures are true
@@ -496,6 +810,7 @@ namespace Microsoft.Dafny
// Annotate the new function so we remember that we introduced it
fWithBody.Attributes = new Attributes("opaque_full", new List<Expression>(), fWithBody.Attributes);
+ fWithBody.Attributes = new Attributes("auto_generated", new List<Expression>(), fWithBody.Attributes);
// Create a lemma to allow the user to selectively reveal the function's body
// That is, given:
@@ -505,7 +820,7 @@ namespace Microsoft.Dafny
// ensures foo(x, y) < 10;
// { x + y }
// We produce:
- // lemma {:axiom} reveal_foo()
+ // lemma {:axiom} {:auto_generated} reveal_foo()
// ensures forall x:int, y:int {:trigger foo(x,y)} :: 0 <= x < 5 && 0 <= y < 5 ==> foo(x,y) == foo_FULL(x,y);
Expression reqExpr = new LiteralExpr(f.tok, true);
foreach (Expression req in f.Req) {
@@ -518,10 +833,7 @@ namespace Microsoft.Dafny
typeVars.Add(cloner.CloneTypeParam(tp));
}
- List<BoundVar> boundVars = new List<BoundVar>();
- foreach (Formal formal in f.Formals) {
- boundVars.Add(new BoundVar(f.tok, formal.Name, cloner.CloneType(formal.Type)));
- }
+ var boundVars = f.Formals.ConvertAll(formal => new BoundVar(formal.tok, formal.Name, cloner.CloneType(formal.Type)));
// Build the implication connecting the function's requires to the connection with the revealed-body version
Func<Function, Expression> func_builder = func =>
@@ -552,6 +864,7 @@ namespace Microsoft.Dafny
// Add an axiom attribute so that the compiler won't complain about the lemma's lack of a body
Attributes lemma_attrs = new Attributes("axiom", new List<Expression>(), null);
+ lemma_attrs = new Attributes("auto_generated", new List<Expression>(), lemma_attrs);
var reveal = new Lemma(f.tok, "reveal_" + f.Name, f.HasStaticKeyword, new List<TypeParameter>(), new List<Formal>(), new List<Formal>(), new List<MaybeFreeExpression>(),
new Specification<FrameExpression>(new List<FrameExpression>(), null), newEnsuresList,
@@ -692,19 +1005,16 @@ namespace Microsoft.Dafny
/// </summary>
public class AutoReqFunctionRewriter : IRewriter {
Function parentFunction;
- Resolver resolver;
OpaqueFunctionRewriter opaqueInfo;
bool containsMatch; // TODO: Track this per-requirement, rather than per-function
- public AutoReqFunctionRewriter(Resolver r, OpaqueFunctionRewriter o) {
- this.resolver = r;
+ public AutoReqFunctionRewriter(ErrorReporter reporter, OpaqueFunctionRewriter o)
+ : base(reporter) {
+ Contract.Requires(reporter != null);
this.opaqueInfo = o;
}
- public void PreResolve(ModuleDefinition m) {
- }
-
- public void PostResolve(ModuleDefinition m) {
+ internal override void PostResolve(ModuleDefinition m) {
var components = m.CallGraph.TopologicallySortedComponents();
foreach (var scComponent in components) { // Visit the call graph bottom up, so anything we call already has its prequisites calculated
@@ -777,9 +1087,6 @@ namespace Microsoft.Dafny
}
}
- public void PostCyclicityResolve(ModuleDefinition m) {
- }
-
Expression subVars(List<Formal> formals, List<Expression> values, Expression e, Expression f_this) {
Contract.Assert(formals != null);
Contract.Assert(values != null);
@@ -810,7 +1117,7 @@ namespace Microsoft.Dafny
}
if (!tip.Equals("")) {
- resolver.ReportAdditionalInformation(f.tok, tip, f.tok.val.Length);
+ reporter.Info(MessageSource.Rewriter, f.tok, tip);
if (DafnyOptions.O.AutoReqPrintFile != null) {
using (System.IO.TextWriter writer = new System.IO.StreamWriter(DafnyOptions.O.AutoReqPrintFile, true)) {
writer.WriteLine(f.Name);
@@ -837,7 +1144,7 @@ namespace Microsoft.Dafny
}
if (!tip.Equals("")) {
- resolver.ReportAdditionalInformation(method.tok, tip, method.tok.val.Length);
+ reporter.Info(MessageSource.Rewriter, method.tok, tip);
if (DafnyOptions.O.AutoReqPrintFile != null) {
using (System.IO.TextWriter writer = new System.IO.StreamWriter(DafnyOptions.O.AutoReqPrintFile, true)) {
writer.WriteLine(method.Name);
@@ -928,6 +1235,10 @@ namespace Microsoft.Dafny
reqs.AddRange(generateAutoReqs(e.Seq));
reqs.AddRange(generateAutoReqs(e.Index));
reqs.AddRange(generateAutoReqs(e.Value));
+ } else if (expr is DatatypeUpdateExpr) {
+ foreach (var ee in expr.SubExpressions) {
+ reqs.AddRange(generateAutoReqs(ee));
+ }
} else if (expr is FunctionCallExpr) {
FunctionCallExpr e = (FunctionCallExpr)expr;
@@ -1032,7 +1343,7 @@ namespace Microsoft.Dafny
Expression allReqsSatisfied = andify(e.Term.tok, auto_reqs);
Expression allReqsSatisfiedAndTerm = Expression.CreateAnd(allReqsSatisfied, e.Term);
e.UpdateTerm(allReqsSatisfiedAndTerm);
- resolver.ReportAdditionalInformation(e.tok, "autoreq added (" + Printer.ExtendedExprToString(allReqsSatisfied) + ") &&", e.tok.val.Length);
+ reporter.Info(MessageSource.Rewriter, e.tok, "autoreq added (" + Printer.ExtendedExprToString(allReqsSatisfied) + ") &&");
}
} else if (expr is SetComprehension) {
var e = (SetComprehension)expr;
@@ -1079,7 +1390,12 @@ namespace Microsoft.Dafny
/// </summary>
public class TimeLimitRewriter : IRewriter
{
- public void PreResolve(ModuleDefinition m) {
+ public TimeLimitRewriter(ErrorReporter reporter)
+ : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PreResolve(ModuleDefinition m) {
foreach (var d in m.TopLevelDecls) {
if (d is ClassDecl) {
var c = (ClassDecl)d;
@@ -1088,15 +1404,15 @@ namespace Microsoft.Dafny
// Check for the timeLimitMultiplier attribute
if (Attributes.Contains(member.Attributes, "timeLimitMultiplier")) {
Attributes attrs = member.Attributes;
- for (; attrs != null; attrs = attrs.Prev) {
- if (attrs.Name == "timeLimitMultiplier") {
- if (attrs.Args.Count == 1 && attrs.Args[0] is LiteralExpr) {
- var arg = attrs.Args[0] as LiteralExpr;
+ foreach (var attr in attrs.AsEnumerable()) {
+ if (attr.Name == "timeLimitMultiplier") {
+ if (attr.Args.Count == 1 && attr.Args[0] is LiteralExpr) {
+ var arg = attr.Args[0] as LiteralExpr;
System.Numerics.BigInteger value = (System.Numerics.BigInteger)arg.Value;
if (value.Sign > 0) {
int current_limit = DafnyOptions.O.ProverKillTime > 0 ? DafnyOptions.O.ProverKillTime : 10; // Default to 10 seconds
- attrs.Args[0] = new LiteralExpr(attrs.Args[0].tok, value * current_limit);
- attrs.Name = "timeLimit";
+ attr.Args[0] = new LiteralExpr(attr.Args[0].tok, value * current_limit);
+ attr.Name = "timeLimit";
}
}
}
@@ -1107,16 +1423,470 @@ namespace Microsoft.Dafny
}
}
}
+ }
+
+
+ class MatchCaseExprSubstituteCloner : Cloner
+ {
+ private List<Tuple<CasePattern, BoundVar>> patternSubst;
+ private BoundVar oldvar;
+ private BoundVar var;
+
+ // the cloner is called after resolving the body of matchexpr, trying
+ // to replace casepattern in the body that has been replaced by bv
+ public MatchCaseExprSubstituteCloner(List<Tuple<CasePattern, BoundVar>> subst) {
+ this.patternSubst = subst;
+ this.oldvar = null;
+ this.var = null;
+ }
+
+ public MatchCaseExprSubstituteCloner(BoundVar oldvar, BoundVar var) {
+ this.patternSubst = null;
+ this.oldvar = oldvar;
+ this.var = var;
+ }
+
+ public override BoundVar CloneBoundVar(BoundVar bv) {
+ // replace bv with this.var if bv == oldvar
+ BoundVar bvNew;
+ if (oldvar != null && bv.Name.Equals(oldvar.Name)) {
+ bvNew = new BoundVar(new AutoGeneratedToken(bv.tok), var.Name, CloneType(bv.Type));
+ } else {
+ bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.Type));
+ }
+ bvNew.IsGhost = bv.IsGhost;
+ return bvNew;
+ }
+
+ public override NameSegment CloneNameSegment(Expression expr) {
+ var e = (NameSegment)expr;
+ if (oldvar != null && e.Name.Equals(oldvar.Name)) {
+ return new NameSegment(new AutoGeneratedToken(e.tok), var.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));
+ } else {
+ return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));
+ }
+ }
+
+ public override Expression CloneApplySuffix(ApplySuffix e) {
+ // if the ApplySuffix matches the CasePattern, then replace it with the BoundVar.
+ CasePattern cp = null;
+ BoundVar bv = null;
+ if (FindMatchingPattern(e, out cp, out bv)) {
+ if (bv.tok is MatchCaseToken) {
+ Contract.Assert(e.Args.Count == cp.Arguments.Count);
+ for (int i = 0; i < e.Args.Count; i++) {
+ ((MatchCaseToken)bv.tok).AddVar(e.Args[i].tok, cp.Arguments[i].Var, false);
+ }
+ }
+ return new NameSegment(new AutoGeneratedToken(e.tok), bv.Name, null);
+ } else {
+ return new ApplySuffix(Tok(e.tok), CloneExpr(e.Lhs), e.Args.ConvertAll(CloneExpr));
+ }
+ }
- public void PostResolve(ModuleDefinition m)
+ private bool FindMatchingPattern(ApplySuffix e, out CasePattern pattern, out BoundVar bv) {
+ pattern = null;
+ bv = null;
+ if (patternSubst == null) {
+ return false;
+ }
+ Expression lhs = e.Lhs;
+ if (!(lhs is NameSegment)) {
+ return false;
+ }
+ string applyName = ((NameSegment)lhs).Name;
+ foreach (Tuple<CasePattern, BoundVar> pair in patternSubst) {
+ CasePattern cp = pair.Item1;
+ string ctorName = cp.Id;
+ if (!(applyName.Equals(ctorName)) || (e.Args.Count != cp.Arguments.Count)) {
+ continue;
+ }
+ bool found = true;
+ for (int i = 0; i < e.Args.Count; i++) {
+ var arg1 = e.Args[i];
+ var arg2 = cp.Arguments[i];
+ if (arg1.Resolved is IdentifierExpr) {
+ var bv1 = ((IdentifierExpr)arg1.Resolved).Var;
+ if (bv1 != arg2.Var) {
+ found = false;
+ }
+ } else {
+ found = false;
+ }
+ }
+ if (found) {
+ pattern = cp;
+ bv = pair.Item2;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ // MatchCaseToken is used to record BoundVars that are consolidated due to rewrite of
+ // nested match patterns. We want to record the original BoundVars that are consolidated
+ // so that they will show up in the IDE correctly.
+ public class MatchCaseToken : AutoGeneratedToken
+ {
+ public readonly List<Tuple<IToken, BoundVar, bool>> varList;
+ public MatchCaseToken(IToken tok)
+ : base(tok) {
+ varList = new List<Tuple<IToken, BoundVar, bool>>();
+ }
+
+ public void AddVar(IToken tok, BoundVar var, bool isDefinition) {
+ varList.Add(new Tuple<IToken, BoundVar, bool>(tok, var, isDefinition));
+ }
+ }
+
+ // A cloner that replace the original token with AutoGeneratedToken.
+ class AutoGeneratedTokenCloner : Cloner
+ {
+ public override IToken Tok(IToken tok) {
+ return new AutoGeneratedToken(tok);
+ }
+ }
+
+ // ===========================================================================================
+
+ public class InductionRewriter : IRewriter {
+ internal InductionRewriter(ErrorReporter reporter) : base(reporter) {
+ Contract.Requires(reporter != null);
+ }
+
+ internal override void PostCyclicityResolve(ModuleDefinition m) {
+ if (DafnyOptions.O.Induction == 0) {
+ // Don't bother inferring :induction attributes. This will also have the effect of not warning about malformed :induction attributes
+ } else {
+ foreach (var decl in m.TopLevelDecls) {
+ if (decl is ClassDecl) {
+ var cl = (ClassDecl)decl;
+ foreach (var member in cl.Members) {
+ if (member is FixpointLemma) {
+ var method = (FixpointLemma)member;
+ ProcessMethodExpressions(method);
+ ComputeLemmaInduction(method.PrefixLemma);
+ ProcessMethodExpressions(method.PrefixLemma);
+ } else if (member is Method) {
+ var method = (Method)member;
+ ComputeLemmaInduction(method);
+ ProcessMethodExpressions(method);
+ } else if (member is FixpointPredicate) {
+ var function = (FixpointPredicate)member;
+ ProcessFunctionExpressions(function);
+ ProcessFunctionExpressions(function.PrefixPredicate);
+ } else if (member is Function) {
+ var function = (Function)member;
+ ProcessFunctionExpressions(function);
+ }
+ }
+ } else if (decl is NewtypeDecl) {
+ var nt = (NewtypeDecl)decl;
+ if (nt.Constraint != null) {
+ var visitor = new Induction_Visitor(this);
+ visitor.Visit(nt.Constraint);
+ }
+ }
+ }
+ }
+ }
+
+ void ProcessMethodExpressions(Method method) {
+ Contract.Requires(method != null);
+ var visitor = new Induction_Visitor(this);
+ method.Req.ForEach(mfe => visitor.Visit(mfe.E));
+ method.Ens.ForEach(mfe => visitor.Visit(mfe.E));
+ if (method.Body != null) {
+ visitor.Visit(method.Body);
+ }
+ }
+
+ void ProcessFunctionExpressions(Function function) {
+ Contract.Requires(function != null);
+ var visitor = new Induction_Visitor(this);
+ function.Req.ForEach(visitor.Visit);
+ function.Ens.ForEach(visitor.Visit);
+ if (function.Body != null) {
+ visitor.Visit(function.Body);
+ }
+ }
+
+ void ComputeLemmaInduction(Method method) {
+ Contract.Requires(method != null);
+ if (method.Body != null && method.IsGhost && method.Mod.Expressions.Count == 0 && method.Outs.Count == 0 && !(method is FixpointLemma)) {
+ var specs = new List<Expression>();
+ method.Req.ForEach(mfe => specs.Add(mfe.E));
+ method.Ens.ForEach(mfe => specs.Add(mfe.E));
+ ComputeInductionVariables(method.tok, method.Ins, specs, method, ref method.Attributes);
+ }
+ }
+
+ void ComputeInductionVariables<VarType>(IToken tok, List<VarType> boundVars, List<Expression> searchExprs, Method lemma, ref Attributes attributes) where VarType : class, IVariable {
+ Contract.Requires(tok != null);
+ Contract.Requires(boundVars != null);
+ Contract.Requires(searchExprs != null);
+ Contract.Requires(DafnyOptions.O.Induction != 0);
+
+ var args = Attributes.FindExpressions(attributes, "induction"); // we only look at the first one we find, since it overrides any other ones
+ if (args == null) {
+ if (DafnyOptions.O.Induction < 2) {
+ // No explicit induction variables and we're asked not to infer anything, so we're done
+ return;
+ } else if (DafnyOptions.O.Induction == 2 && lemma != null) {
+ // We're asked to infer induction variables only for quantifiers, not for lemmas
+ return;
+ }
+ // GO INFER below (only select boundVars)
+ } else if (args.Count == 0) {
+ // {:induction} is treated the same as {:induction true}, which says to automatically infer induction variables
+ // GO INFER below (all boundVars)
+ } else if (args.Count == 1 && args[0] is LiteralExpr && ((LiteralExpr)args[0]).Value is bool) {
+ // {:induction false} or {:induction true}
+ if (!(bool)((LiteralExpr)args[0]).Value) {
+ // we're told not to infer anything
+ return;
+ }
+ // GO INFER below (all boundVars)
+ } else {
+ // Here, we're expecting the arguments to {:induction args} to be a sublist of "boundVars".
+ var goodArguments = new List<Expression>();
+ var i = 0;
+ foreach (var arg in args) {
+ var ie = arg.Resolved as IdentifierExpr;
+ if (ie != null) {
+ var j = boundVars.FindIndex(i, v => v == ie.Var);
+ if (i <= j) {
+ goodArguments.Add(ie);
+ i = j;
+ continue;
+ }
+ if (0 <= boundVars.FindIndex(v => v == ie.Var)) {
+ reporter.Warning(MessageSource.Rewriter, arg.tok, "{0}s given as :induction arguments must be given in the same order as in the {1}; ignoring attribute",
+ lemma != null ? "lemma parameter" : "bound variable", lemma != null ? "lemma" : "quantifier");
+ return;
+ }
+ }
+ reporter.Warning(MessageSource.Rewriter, arg.tok, "invalid :induction attribute argument; expected {0}{1}; ignoring attribute",
+ i == 0 ? "'false' or 'true' or " : "",
+ lemma != null ? "lemma parameter" : "bound variable");
+ return;
+ }
+ // The argument list was legal, so let's use it for the _induction attribute
+ attributes = new Attributes("_induction", goodArguments, attributes);
+ return;
+ }
+
+ // Okay, here we go, coming up with good induction setting for the given situation
+ var inductionVariables = new List<Expression>();
+ foreach (IVariable n in boundVars) {
+ if (!n.Type.IsTypeParameter && (args != null || searchExprs.Exists(expr => VarOccursInArgumentToRecursiveFunction(expr, n)))) {
+ inductionVariables.Add(new IdentifierExpr(n));
+ }
+ }
+ if (inductionVariables.Count != 0) {
+ // We found something usable, so let's record that in an attribute
+ attributes = new Attributes("_induction", inductionVariables, attributes);
+ // And since we're inferring something, let's also report that in a hover text.
+ var s = Printer.OneAttributeToString(attributes, "induction");
+ if (lemma is PrefixLemma) {
+ s = lemma.Name + " " + s;
+ }
+ reporter.Info(MessageSource.Rewriter, tok, s);
+ }
+ }
+ class Induction_Visitor : BottomUpVisitor
{
- // Nothing to do here
+ readonly InductionRewriter IndRewriter;
+ public Induction_Visitor(InductionRewriter inductionRewriter) {
+ Contract.Requires(inductionRewriter != null);
+ IndRewriter = inductionRewriter;
+ }
+ protected override void VisitOneExpr(Expression expr) {
+ var q = expr as QuantifierExpr;
+ if (q != null && q.SplitQuantifier == null) {
+ IndRewriter.ComputeInductionVariables(q.tok, q.BoundVars, new List<Expression>() { q.LogicalBody() }, null, ref q.Attributes);
+ }
+ }
+ void VisitInductionStmt(Statement stmt) {
+ Contract.Requires(stmt != null);
+ // visit a selection of subexpressions
+ if (stmt is AssertStmt) {
+ var s = (AssertStmt)stmt;
+ Visit(s.Expr);
+ }
+ // recursively visit all substatements
+ foreach (var s in stmt.SubStatements) {
+ VisitInductionStmt(s);
+ }
+ }
}
- public void PostCyclicityResolve(ModuleDefinition m) {
- // Nothing to do here
+ /// <summary>
+ /// Returns 'true' iff by looking at 'expr' the Induction Heuristic determines that induction should be applied to 'n'.
+ /// More precisely:
+ /// DafnyInductionHeuristic Return 'true'
+ /// ----------------------- -------------
+ /// 0 always
+ /// 1 if 'n' occurs as any subexpression (of 'expr')
+ /// 2 if 'n' occurs as any subexpression of any index argument of an array/sequence select expression or any argument to a recursive function
+ /// 3 if 'n' occurs as a prominent subexpression of any index argument of an array/sequence select expression or any argument to a recursive function
+ /// 4 if 'n' occurs as any subexpression of any argument to a recursive function
+ /// 5 if 'n' occurs as a prominent subexpression of any argument to a recursive function
+ /// 6 if 'n' occurs as a prominent subexpression of any decreases-influencing argument to a recursive function
+ /// Parameter 'n' is allowed to be a ThisSurrogate.
+ /// </summary>
+ public static bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n) {
+ switch (DafnyOptions.O.InductionHeuristic) {
+ case 0: return true;
+ case 1: return Translator.ContainsFreeVariable(expr, false, n);
+ default: return VarOccursInArgumentToRecursiveFunction(expr, n, false);
+ }
}
+ /// <summary>
+ /// Worker routine for VarOccursInArgumentToRecursiveFunction(expr,n), where the additional parameter 'exprIsProminent' says whether or
+ /// not 'expr' has prominent status in its context.
+ /// DafnyInductionHeuristic cases 0 and 1 are assumed to be handled elsewhere (i.e., a precondition of this method is DafnyInductionHeuristic is at least 2).
+ /// Parameter 'n' is allowed to be a ThisSurrogate.
+ /// </summary>
+ static bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n, bool exprIsProminent) {
+ Contract.Requires(expr != null);
+ Contract.Requires(n != null);
+
+ // The following variable is what gets passed down to recursive calls if the subexpression does not itself acquire prominent status.
+ var subExprIsProminent = DafnyOptions.O.InductionHeuristic == 2 || DafnyOptions.O.InductionHeuristic == 4 ? /*once prominent, always prominent*/exprIsProminent : /*reset the prominent status*/false;
+
+ if (expr is IdentifierExpr) {
+ var e = (IdentifierExpr)expr;
+ return exprIsProminent && e.Var == n;
+ } else if (expr is SeqSelectExpr) {
+ var e = (SeqSelectExpr)expr;
+ var q = DafnyOptions.O.InductionHeuristic < 4 || subExprIsProminent;
+ return VarOccursInArgumentToRecursiveFunction(e.Seq, n, subExprIsProminent) || // this subexpression does not acquire "prominent" status
+ (e.E0 != null && VarOccursInArgumentToRecursiveFunction(e.E0, n, q)) || // this one does (unless arrays/sequences are excluded)
+ (e.E1 != null && VarOccursInArgumentToRecursiveFunction(e.E1, n, q)); // ditto
+ } else if (expr is MultiSelectExpr) {
+ var e = (MultiSelectExpr)expr;
+ var q = DafnyOptions.O.InductionHeuristic < 4 || subExprIsProminent;
+ return VarOccursInArgumentToRecursiveFunction(e.Array, n, subExprIsProminent) ||
+ e.Indices.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));
+ } else if (expr is FunctionCallExpr) {
+ var e = (FunctionCallExpr)expr;
+ // For recursive functions: arguments are "prominent"
+ // For non-recursive function: arguments are "prominent" if the call is
+ var rec = e.Function.IsRecursive && e.CoCall != FunctionCallExpr.CoCallResolution.Yes;
+ var decr = e.Function.Decreases.Expressions;
+ bool variantArgument;
+ if (DafnyOptions.O.InductionHeuristic < 6) {
+ variantArgument = rec;
+ } else {
+ // The receiver is considered to be "variant" if the function is recursive and the receiver participates
+ // in the effective decreases clause of the function. The receiver participates if it's a free variable
+ // of a term in the explicit decreases clause.
+ variantArgument = rec && decr.Exists(ee => Translator.ContainsFreeVariable(ee, true, null));
+ }
+ if (VarOccursInArgumentToRecursiveFunction(e.Receiver, n, variantArgument || subExprIsProminent)) {
+ return true;
+ }
+ Contract.Assert(e.Function.Formals.Count == e.Args.Count);
+ for (int i = 0; i < e.Function.Formals.Count; i++) {
+ var f = e.Function.Formals[i];
+ var exp = e.Args[i];
+ if (DafnyOptions.O.InductionHeuristic < 6) {
+ variantArgument = rec;
+ } else if (rec) {
+ // The argument position is considered to be "variant" if the function is recursive and...
+ // ... it has something to do with why the callee is well-founded, which happens when...
+ if (f is ImplicitFormal) {
+ // ... it is the argument is the implicit _k parameter, which is always first in the effective decreases clause of a prefix lemma, or
+ variantArgument = true;
+ } else if (decr.Exists(ee => Translator.ContainsFreeVariable(ee, false, f))) {
+ // ... it participates in the effective decreases clause of the function, which happens when it is
+ // a free variable of a term in the explicit decreases clause, or
+ variantArgument = true;
+ } else {
+ // ... the callee is a prefix predicate.
+ variantArgument = true;
+ }
+ }
+ if (VarOccursInArgumentToRecursiveFunction(exp, n, variantArgument || subExprIsProminent)) {
+ return true;
+ }
+ }
+ return false;
+ } else if (expr is TernaryExpr) {
+ var e = (TernaryExpr)expr;
+ switch (e.Op) {
+ case TernaryExpr.Opcode.PrefixEqOp:
+ case TernaryExpr.Opcode.PrefixNeqOp:
+ return VarOccursInArgumentToRecursiveFunction(e.E0, n, true) ||
+ VarOccursInArgumentToRecursiveFunction(e.E1, n, subExprIsProminent) ||
+ VarOccursInArgumentToRecursiveFunction(e.E2, n, subExprIsProminent);
+ default:
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected ternary expression
+ }
+ } else if (expr is DatatypeValue) {
+ var e = (DatatypeValue)expr;
+ var q = n.Type.IsDatatype ? exprIsProminent : subExprIsProminent; // prominent status continues, if we're looking for a variable whose type is a datatype
+ return e.Arguments.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));
+ } else if (expr is UnaryExpr) {
+ var e = (UnaryExpr)expr;
+ // both Not and SeqLength preserve prominence
+ return VarOccursInArgumentToRecursiveFunction(e.E, n, exprIsProminent);
+ } else if (expr is BinaryExpr) {
+ var e = (BinaryExpr)expr;
+ bool q;
+ switch (e.ResolvedOp) {
+ case BinaryExpr.ResolvedOpcode.Add:
+ case BinaryExpr.ResolvedOpcode.Sub:
+ case BinaryExpr.ResolvedOpcode.Mul:
+ case BinaryExpr.ResolvedOpcode.Div:
+ case BinaryExpr.ResolvedOpcode.Mod:
+ case BinaryExpr.ResolvedOpcode.Union:
+ case BinaryExpr.ResolvedOpcode.Intersection:
+ case BinaryExpr.ResolvedOpcode.SetDifference:
+ case BinaryExpr.ResolvedOpcode.Concat:
+ // these operators preserve prominence
+ q = exprIsProminent;
+ break;
+ default:
+ // whereas all other binary operators do not
+ q = subExprIsProminent;
+ break;
+ }
+ return VarOccursInArgumentToRecursiveFunction(e.E0, n, q) ||
+ VarOccursInArgumentToRecursiveFunction(e.E1, n, q);
+ } else if (expr is StmtExpr) {
+ var e = (StmtExpr)expr;
+ // ignore the statement
+ return VarOccursInArgumentToRecursiveFunction(e.E, n);
+
+ } else if (expr is ITEExpr) {
+ var e = (ITEExpr)expr;
+ return VarOccursInArgumentToRecursiveFunction(e.Test, n, subExprIsProminent) || // test is not "prominent"
+ VarOccursInArgumentToRecursiveFunction(e.Thn, n, exprIsProminent) || // but the two branches are
+ VarOccursInArgumentToRecursiveFunction(e.Els, n, exprIsProminent);
+ } else if (expr is OldExpr ||
+ expr is ConcreteSyntaxExpression ||
+ expr is BoxingCastExpr ||
+ expr is UnboxingCastExpr) {
+ foreach (var exp in expr.SubExpressions) {
+ if (VarOccursInArgumentToRecursiveFunction(exp, n, exprIsProminent)) { // maintain prominence
+ return true;
+ }
+ }
+ return false;
+ } else {
+ // in all other cases, reset the prominence status and recurse on the subexpressions
+ foreach (var exp in expr.SubExpressions) {
+ if (VarOccursInArgumentToRecursiveFunction(exp, n, subExprIsProminent)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
}
diff --git a/Source/Dafny/Scanner.cs b/Source/Dafny/Scanner.cs
index 3427477b..cb3dbe7e 100644
--- a/Source/Dafny/Scanner.cs
+++ b/Source/Dafny/Scanner.cs
@@ -211,23 +211,35 @@ public class UTF8Buffer: Buffer {
public class Scanner {
const char EOL = '\n';
const int eofSym = 0; /* pdt */
- const int maxT = 136;
- const int noSym = 136;
+ const int maxT = 140;
+ const int noSym = 140;
[ContractInvariantMethod]
void objectInvariant(){
- Contract.Invariant(buffer!=null);
+ Contract.Invariant(this._buffer != null);
Contract.Invariant(t != null);
Contract.Invariant(start != null);
Contract.Invariant(tokens != null);
Contract.Invariant(pt != null);
Contract.Invariant(tval != null);
Contract.Invariant(Filename != null);
+ Contract.Invariant(FullFilename != null);
Contract.Invariant(errorHandler != null);
}
- public Buffer/*!*/ buffer; // scanner buffer
+ private Buffer/*!*/ _buffer; // scanner buffer
+
+ public Buffer/*!*/ buffer {
+ get {
+ Contract.Ensures(Contract.Result<Buffer>() != null);
+ return this._buffer;
+ }
+ set {
+ Contract.Requires(value != null);
+ this._buffer = value;
+ }
+ }
Token/*!*/ t; // current token
int ch; // current input character
@@ -247,51 +259,53 @@ public class Scanner {
private string/*!*/ Filename;
private Errors/*!*/ errorHandler;
+ internal string/*!*/ FullFilename { get; private set; }
+
static Scanner() {
start = new Hashtable(128);
for (int i = 63; i <= 63; ++i) start[i] = 1;
for (int i = 65; i <= 90; ++i) start[i] = 1;
for (int i = 95; i <= 95; ++i) start[i] = 1;
for (int i = 98; i <= 122; ++i) start[i] = 1;
- for (int i = 49; i <= 57; ++i) start[i] = 48;
- start[97] = 49;
- start[39] = 50;
- start[48] = 51;
+ for (int i = 49; i <= 57; ++i) start[i] = 49;
+ start[97] = 50;
+ start[39] = 51;
+ start[48] = 52;
start[34] = 21;
start[64] = 26;
start[58] = 89;
start[44] = 29;
start[124] = 90;
- start[8226] = 31;
+ start[8226] = 32;
start[46] = 91;
- start[59] = 32;
+ start[59] = 33;
start[61] = 92;
start[45] = 93;
- start[123] = 35;
- start[125] = 36;
- start[91] = 37;
- start[93] = 38;
- start[40] = 39;
- start[41] = 40;
+ start[123] = 36;
+ start[125] = 37;
+ start[91] = 38;
+ start[93] = 39;
+ start[40] = 40;
+ start[41] = 41;
start[60] = 94;
start[62] = 95;
start[33] = 96;
- start[8800] = 42;
- start[42] = 43;
- start[96] = 66;
- start[35] = 69;
- start[8804] = 71;
- start[8805] = 72;
- start[8660] = 74;
- start[8658] = 76;
- start[8656] = 77;
- start[38] = 78;
- start[8743] = 80;
- start[8744] = 82;
- start[172] = 83;
- start[8704] = 84;
- start[8707] = 85;
- start[43] = 86;
+ start[8800] = 43;
+ start[42] = 44;
+ start[43] = 67;
+ start[96] = 68;
+ start[35] = 70;
+ start[8804] = 72;
+ start[8805] = 73;
+ start[8660] = 75;
+ start[8658] = 77;
+ start[8656] = 78;
+ start[38] = 79;
+ start[8743] = 81;
+ start[8744] = 83;
+ start[172] = 84;
+ start[8704] = 85;
+ start[8707] = 86;
start[47] = 87;
start[37] = 88;
start[Buffer.EOF] = -1;
@@ -299,15 +313,16 @@ public class Scanner {
}
// [NotDelayed]
- public Scanner (string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() {
- Contract.Requires(fileName != null);
- Contract.Requires(errorHandler != null);
+ public Scanner (string/*!*/ fullFilename, string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() {
+ Contract.Requires(fileName != null);
+ Contract.Requires(errorHandler != null);
this.errorHandler = errorHandler;
pt = tokens = new Token(); // first token is a dummy
t = new Token(); // dummy because t is a non-null field
try {
Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
- buffer = new Buffer(stream, false);
+ this._buffer = new Buffer(stream, false);
+ this.FullFilename = fullFilename;
Filename = useBaseName? GetBaseName(fileName): fileName;
Init();
} catch (IOException) {
@@ -316,21 +331,22 @@ public class Scanner {
}
// [NotDelayed]
- public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fileName, bool useBaseName = false) : base() {
- Contract.Requires(s != null);
- Contract.Requires(errorHandler != null);
- Contract.Requires(fileName != null);
+ public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fullFilename, string/*!*/ fileName, bool useBaseName = false) : base() {
+ Contract.Requires(s != null);
+ Contract.Requires(errorHandler != null);
+ Contract.Requires(fileName != null);
pt = tokens = new Token(); // first token is a dummy
t = new Token(); // dummy because t is a non-null field
- buffer = new Buffer(s, true);
+ this._buffer = new Buffer(s, true);
this.errorHandler = errorHandler;
+ this.FullFilename = fullFilename;
this.Filename = useBaseName? GetBaseName(fileName) : fileName;
Init();
}
- string GetBaseName(string fileName) {
- return System.IO.Path.GetFileName(fileName); // Return basename
- }
+ string GetBaseName(string fileName) {
+ return System.IO.Path.GetFileName(fileName); // Return basename
+ }
void Init() {
pos = -1; line = 1; col = 0;
@@ -503,75 +519,79 @@ public class Scanner {
case "object": t.kind = 11; break;
case "string": t.kind = 12; break;
case "set": t.kind = 13; break;
- case "multiset": t.kind = 14; break;
- case "seq": t.kind = 15; break;
- case "map": t.kind = 16; break;
- case "imap": t.kind = 17; break;
- case "assume": t.kind = 29; break;
- case "calc": t.kind = 30; break;
- case "case": t.kind = 31; break;
- case "then": t.kind = 32; break;
- case "else": t.kind = 33; break;
- case "decreases": t.kind = 34; break;
- case "invariant": t.kind = 35; break;
- case "function": t.kind = 36; break;
- case "predicate": t.kind = 37; break;
- case "inductive": t.kind = 38; break;
- case "lemma": t.kind = 39; break;
- case "copredicate": t.kind = 40; break;
- case "modifies": t.kind = 41; break;
- case "reads": t.kind = 42; break;
- case "requires": t.kind = 43; break;
- case "include": t.kind = 58; break;
- case "abstract": t.kind = 59; break;
- case "module": t.kind = 60; break;
- case "refines": t.kind = 61; break;
- case "import": t.kind = 62; break;
- case "opened": t.kind = 63; break;
- case "as": t.kind = 65; break;
- case "default": t.kind = 66; break;
- case "class": t.kind = 67; break;
- case "extends": t.kind = 68; break;
- case "trait": t.kind = 69; break;
- case "ghost": t.kind = 70; break;
- case "static": t.kind = 71; break;
- case "protected": t.kind = 72; break;
- case "datatype": t.kind = 73; break;
- case "codatatype": t.kind = 74; break;
- case "var": t.kind = 75; break;
- case "newtype": t.kind = 76; break;
- case "type": t.kind = 77; break;
- case "iterator": t.kind = 78; break;
- case "yields": t.kind = 79; break;
- case "returns": t.kind = 80; break;
- case "method": t.kind = 81; break;
- case "colemma": t.kind = 82; break;
- case "comethod": t.kind = 83; break;
- case "constructor": t.kind = 84; break;
- case "free": t.kind = 85; break;
- case "ensures": t.kind = 86; break;
- case "yield": t.kind = 87; break;
- case "label": t.kind = 89; break;
- case "break": t.kind = 90; break;
- case "where": t.kind = 91; break;
- case "return": t.kind = 93; break;
- case "new": t.kind = 95; break;
- case "if": t.kind = 96; break;
- case "while": t.kind = 97; break;
- case "match": t.kind = 98; break;
- case "assert": t.kind = 99; break;
- case "print": t.kind = 100; break;
- case "forall": t.kind = 101; break;
- case "parallel": t.kind = 102; break;
- case "modify": t.kind = 103; break;
- case "exists": t.kind = 122; break;
- case "in": t.kind = 124; break;
- case "false": t.kind = 129; break;
- case "true": t.kind = 130; break;
- case "null": t.kind = 131; break;
- case "this": t.kind = 132; break;
- case "fresh": t.kind = 133; break;
- case "old": t.kind = 134; break;
+ case "iset": t.kind = 14; break;
+ case "multiset": t.kind = 15; break;
+ case "seq": t.kind = 16; break;
+ case "map": t.kind = 17; break;
+ case "imap": t.kind = 18; break;
+ case "assume": t.kind = 31; break;
+ case "calc": t.kind = 32; break;
+ case "case": t.kind = 33; break;
+ case "then": t.kind = 34; break;
+ case "else": t.kind = 35; break;
+ case "decreases": t.kind = 36; break;
+ case "invariant": t.kind = 37; break;
+ case "function": t.kind = 38; break;
+ case "predicate": t.kind = 39; break;
+ case "inductive": t.kind = 40; break;
+ case "lemma": t.kind = 41; break;
+ case "copredicate": t.kind = 42; break;
+ case "modifies": t.kind = 43; break;
+ case "reads": t.kind = 44; break;
+ case "requires": t.kind = 45; break;
+ case "include": t.kind = 60; break;
+ case "abstract": t.kind = 61; break;
+ case "ghost": t.kind = 62; break;
+ case "static": t.kind = 63; break;
+ case "protected": t.kind = 64; break;
+ case "extern": t.kind = 65; break;
+ case "module": t.kind = 66; break;
+ case "exclusively": t.kind = 67; break;
+ case "refines": t.kind = 68; break;
+ case "import": t.kind = 69; break;
+ case "opened": t.kind = 70; break;
+ case "as": t.kind = 72; break;
+ case "default": t.kind = 73; break;
+ case "export": t.kind = 74; break;
+ case "extends": t.kind = 75; break;
+ case "class": t.kind = 77; break;
+ case "trait": t.kind = 78; break;
+ case "datatype": t.kind = 79; break;
+ case "codatatype": t.kind = 80; break;
+ case "var": t.kind = 81; break;
+ case "newtype": t.kind = 82; break;
+ case "type": t.kind = 83; break;
+ case "iterator": t.kind = 84; break;
+ case "yields": t.kind = 85; break;
+ case "returns": t.kind = 86; break;
+ case "method": t.kind = 87; break;
+ case "colemma": t.kind = 88; break;
+ case "comethod": t.kind = 89; break;
+ case "constructor": t.kind = 90; break;
+ case "free": t.kind = 91; break;
+ case "ensures": t.kind = 92; break;
+ case "yield": t.kind = 93; break;
+ case "label": t.kind = 95; break;
+ case "break": t.kind = 96; break;
+ case "where": t.kind = 97; break;
+ case "return": t.kind = 99; break;
+ case "new": t.kind = 100; break;
+ case "if": t.kind = 101; break;
+ case "while": t.kind = 102; break;
+ case "match": t.kind = 103; break;
+ case "assert": t.kind = 104; break;
+ case "print": t.kind = 105; break;
+ case "forall": t.kind = 106; break;
+ case "parallel": t.kind = 107; break;
+ case "modify": t.kind = 108; break;
+ case "exists": t.kind = 127; break;
+ case "in": t.kind = 129; break;
+ case "false": t.kind = 133; break;
+ case "true": t.kind = 134; break;
+ case "null": t.kind = 135; break;
+ case "this": t.kind = 136; break;
+ case "fresh": t.kind = 137; break;
+ case "old": t.kind = 138; break;
default: break;
}
}
@@ -674,11 +694,11 @@ public class Scanner {
if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {AddCh(); goto case 15;}
else {goto case 0;}
case 20:
- {t.kind = 18; break;}
+ {t.kind = 19; break;}
case 21:
if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 21;}
else if (ch == '"') {AddCh(); goto case 28;}
- else if (ch == 92) {AddCh(); goto case 54;}
+ else if (ch == 92) {AddCh(); goto case 55;}
else {goto case 0;}
case 22:
if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {AddCh(); goto case 23;}
@@ -697,239 +717,239 @@ public class Scanner {
else {goto case 0;}
case 27:
if (ch <= '!' || ch >= '#' && ch <= 65535) {AddCh(); goto case 27;}
- else if (ch == '"') {AddCh(); goto case 55;}
+ else if (ch == '"') {AddCh(); goto case 56;}
else {goto case 0;}
case 28:
- {t.kind = 19; break;}
+ {t.kind = 20; break;}
case 29:
- {t.kind = 21; break;}
+ {t.kind = 22; break;}
case 30:
- {t.kind = 23; break;}
- case 31:
{t.kind = 24; break;}
+ case 31:
+ {t.kind = 25; break;}
case 32:
{t.kind = 26; break;}
case 33:
- {t.kind = 27; break;}
- case 34:
{t.kind = 28; break;}
+ case 34:
+ {t.kind = 29; break;}
case 35:
- {t.kind = 44; break;}
+ {t.kind = 30; break;}
case 36:
- {t.kind = 45; break;}
- case 37:
{t.kind = 46; break;}
- case 38:
+ case 37:
{t.kind = 47; break;}
- case 39:
+ case 38:
{t.kind = 48; break;}
- case 40:
+ case 39:
{t.kind = 49; break;}
+ case 40:
+ {t.kind = 50; break;}
case 41:
- {t.kind = 53; break;}
+ {t.kind = 51; break;}
case 42:
- {t.kind = 54; break;}
- case 43:
{t.kind = 55; break;}
+ case 43:
+ {t.kind = 56; break;}
case 44:
- if (ch == 'n') {AddCh(); goto case 45;}
- else {goto case 0;}
+ {t.kind = 57; break;}
case 45:
- if (ch <= '&' || ch >= '(' && ch <= '/' || ch >= ':' && ch <= '>' || ch == '@' || ch >= '[' && ch <= '^' || ch == '`' || ch >= '{' && ch <= 65535) {apx++; AddCh(); goto case 46;}
+ if (ch == 'n') {AddCh(); goto case 46;}
else {goto case 0;}
case 46:
+ if (ch <= '&' || ch >= '(' && ch <= '/' || ch >= ':' && ch <= '>' || ch == '@' || ch >= '[' && ch <= '^' || ch == '`' || ch >= '{' && ch <= 65535) {apx++; AddCh(); goto case 47;}
+ else {goto case 0;}
+ case 47:
{
tlen -= apx;
SetScannerBehindT();
- t.kind = 56; break;}
- case 47:
- {t.kind = 57; break;}
+ t.kind = 58; break;}
case 48:
+ {t.kind = 59; break;}
+ case 49:
recEnd = pos; recKind = 2;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 48;}
- else if (ch == '_') {AddCh(); goto case 56;}
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 49;}
+ else if (ch == '_') {AddCh(); goto case 57;}
else if (ch == '.') {AddCh(); goto case 12;}
else {t.kind = 2; break;}
- case 49:
+ case 50:
recEnd = pos; recKind = 1;
if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'q' || ch >= 's' && ch <= 'z') {AddCh(); goto case 2;}
- else if (ch == 'r') {AddCh(); goto case 57;}
+ else if (ch == 'r') {AddCh(); goto case 58;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
- case 50:
+ case 51:
recEnd = pos; recKind = 1;
- if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 58;}
- else if (ch == 39) {AddCh(); goto case 59;}
+ if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 59;}
+ else if (ch == 39) {AddCh(); goto case 60;}
else if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '&' || ch >= '(' && ch <= '/' || ch >= ':' && ch <= '>' || ch == '@' || ch == '[' || ch >= ']' && ch <= '^' || ch == '`' || ch >= '{' && ch <= 65535) {AddCh(); goto case 15;}
- else if (ch == 92) {AddCh(); goto case 53;}
+ else if (ch == 92) {AddCh(); goto case 54;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
- case 51:
+ case 52:
recEnd = pos; recKind = 2;
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 48;}
- else if (ch == '_') {AddCh(); goto case 56;}
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 49;}
+ else if (ch == '_') {AddCh(); goto case 57;}
else if (ch == 'x') {AddCh(); goto case 9;}
else if (ch == '.') {AddCh(); goto case 12;}
else {t.kind = 2; break;}
- case 52:
+ case 53:
recEnd = pos; recKind = 1;
- if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 52;}
+ if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 53;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
- case 53:
+ case 54:
if (ch == '"' || ch == 39 || ch == '0' || ch == 92 || ch == 'n' || ch == 'r' || ch == 't') {AddCh(); goto case 15;}
else if (ch == 'u') {AddCh(); goto case 16;}
else {goto case 0;}
- case 54:
+ case 55:
if (ch == '"' || ch == 39 || ch == '0' || ch == 92 || ch == 'n' || ch == 'r' || ch == 't') {AddCh(); goto case 21;}
else if (ch == 'u') {AddCh(); goto case 22;}
else {goto case 0;}
- case 55:
- recEnd = pos; recKind = 19;
- if (ch == '"') {AddCh(); goto case 27;}
- else {t.kind = 19; break;}
case 56:
- if (ch >= '0' && ch <= '9') {AddCh(); goto case 48;}
- else {goto case 0;}
+ recEnd = pos; recKind = 20;
+ if (ch == '"') {AddCh(); goto case 27;}
+ else {t.kind = 20; break;}
case 57:
- recEnd = pos; recKind = 1;
- if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'q' || ch >= 's' && ch <= 'z') {AddCh(); goto case 3;}
- else if (ch == 'r') {AddCh(); goto case 60;}
- else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
+ if (ch >= '0' && ch <= '9') {AddCh(); goto case 49;}
+ else {goto case 0;}
case 58:
recEnd = pos; recKind = 1;
- if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 61;}
- else if (ch == 39) {AddCh(); goto case 62;}
+ if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'q' || ch >= 's' && ch <= 'z') {AddCh(); goto case 3;}
+ else if (ch == 'r') {AddCh(); goto case 61;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
case 59:
recEnd = pos; recKind = 1;
- if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 61;}
- else if (ch == 39) {AddCh(); goto case 7;}
+ if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 62;}
+ else if (ch == 39) {AddCh(); goto case 63;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
case 60:
recEnd = pos; recKind = 1;
- if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'b' && ch <= 'z') {AddCh(); goto case 4;}
- else if (ch == 'a') {AddCh(); goto case 63;}
+ if (ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 62;}
+ else if (ch == 39) {AddCh(); goto case 7;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
case 61:
recEnd = pos; recKind = 1;
- if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 8;}
+ if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'b' && ch <= 'z') {AddCh(); goto case 4;}
+ else if (ch == 'a') {AddCh(); goto case 64;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
case 62:
- recEnd = pos; recKind = 18;
+ recEnd = pos; recKind = 1;
if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 8;}
- else {t.kind = 18; break;}
+ else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
case 63:
+ recEnd = pos; recKind = 19;
+ if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 8;}
+ else {t.kind = 19; break;}
+ case 64:
recEnd = pos; recKind = 1;
if (ch == 39 || ch >= '0' && ch <= '9' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'x' || ch == 'z') {AddCh(); goto case 5;}
- else if (ch == 'y') {AddCh(); goto case 64;}
+ else if (ch == 'y') {AddCh(); goto case 65;}
else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}
- case 64:
+ case 65:
recEnd = pos; recKind = 5;
if (ch == 39 || ch == '0' || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 6;}
- else if (ch >= '1' && ch <= '9') {AddCh(); goto case 65;}
+ else if (ch >= '1' && ch <= '9') {AddCh(); goto case 66;}
else {t.kind = 5; break;}
- case 65:
+ case 66:
recEnd = pos; recKind = 5;
- if (ch == 39 || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 52;}
- else if (ch >= '0' && ch <= '9') {AddCh(); goto case 65;}
+ if (ch == 39 || ch == '?' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 53;}
+ else if (ch >= '0' && ch <= '9') {AddCh(); goto case 66;}
else {t.kind = 5; break;}
- case 66:
- {t.kind = 88; break;}
case 67:
- {t.kind = 92; break;}
+ {t.kind = 76; break;}
case 68:
{t.kind = 94; break;}
case 69:
- {t.kind = 104; break;}
+ {t.kind = 98; break;}
case 70:
- {t.kind = 106; break;}
+ {t.kind = 109; break;}
case 71:
- {t.kind = 107; break;}
+ {t.kind = 111; break;}
case 72:
- {t.kind = 108; break;}
+ {t.kind = 112; break;}
case 73:
- {t.kind = 109; break;}
+ {t.kind = 113; break;}
case 74:
- {t.kind = 110; break;}
+ {t.kind = 114; break;}
case 75:
- {t.kind = 111; break;}
+ {t.kind = 115; break;}
case 76:
- {t.kind = 112; break;}
+ {t.kind = 116; break;}
case 77:
- {t.kind = 114; break;}
+ {t.kind = 117; break;}
case 78:
- if (ch == '&') {AddCh(); goto case 79;}
- else {goto case 0;}
+ {t.kind = 119; break;}
case 79:
- {t.kind = 115; break;}
+ if (ch == '&') {AddCh(); goto case 80;}
+ else {goto case 0;}
case 80:
- {t.kind = 116; break;}
+ {t.kind = 120; break;}
case 81:
- {t.kind = 117; break;}
+ {t.kind = 121; break;}
case 82:
- {t.kind = 118; break;}
+ {t.kind = 122; break;}
case 83:
- {t.kind = 120; break;}
+ {t.kind = 123; break;}
case 84:
- {t.kind = 121; break;}
+ {t.kind = 125; break;}
case 85:
- {t.kind = 123; break;}
+ {t.kind = 126; break;}
case 86:
- {t.kind = 125; break;}
+ {t.kind = 128; break;}
case 87:
- {t.kind = 127; break;}
+ {t.kind = 131; break;}
case 88:
- {t.kind = 128; break;}
+ {t.kind = 132; break;}
case 89:
- recEnd = pos; recKind = 20;
+ recEnd = pos; recKind = 21;
if (ch == ':') {AddCh(); goto case 30;}
- else if (ch == '=') {AddCh(); goto case 67;}
- else if (ch == '|') {AddCh(); goto case 68;}
- else {t.kind = 20; break;}
+ else if (ch == '|') {AddCh(); goto case 31;}
+ else if (ch == '=') {AddCh(); goto case 69;}
+ else {t.kind = 21; break;}
case 90:
- recEnd = pos; recKind = 22;
- if (ch == '|') {AddCh(); goto case 81;}
- else {t.kind = 22; break;}
+ recEnd = pos; recKind = 23;
+ if (ch == '|') {AddCh(); goto case 82;}
+ else {t.kind = 23; break;}
case 91:
- recEnd = pos; recKind = 25;
+ recEnd = pos; recKind = 27;
if (ch == '.') {AddCh(); goto case 97;}
- else {t.kind = 25; break;}
+ else {t.kind = 27; break;}
case 92:
- recEnd = pos; recKind = 64;
- if (ch == '>') {AddCh(); goto case 33;}
+ recEnd = pos; recKind = 71;
+ if (ch == '>') {AddCh(); goto case 34;}
else if (ch == '=') {AddCh(); goto case 98;}
- else {t.kind = 64; break;}
+ else {t.kind = 71; break;}
case 93:
- recEnd = pos; recKind = 126;
- if (ch == '>') {AddCh(); goto case 34;}
- else {t.kind = 126; break;}
+ recEnd = pos; recKind = 130;
+ if (ch == '>') {AddCh(); goto case 35;}
+ else {t.kind = 130; break;}
case 94:
- recEnd = pos; recKind = 50;
+ recEnd = pos; recKind = 52;
if (ch == '=') {AddCh(); goto case 99;}
- else {t.kind = 50; break;}
+ else {t.kind = 52; break;}
case 95:
- recEnd = pos; recKind = 51;
- if (ch == '=') {AddCh(); goto case 70;}
- else {t.kind = 51; break;}
+ recEnd = pos; recKind = 53;
+ if (ch == '=') {AddCh(); goto case 71;}
+ else {t.kind = 53; break;}
case 96:
- recEnd = pos; recKind = 119;
- if (ch == '=') {AddCh(); goto case 41;}
- else if (ch == 'i') {AddCh(); goto case 44;}
- else {t.kind = 119; break;}
+ recEnd = pos; recKind = 124;
+ if (ch == '=') {AddCh(); goto case 42;}
+ else if (ch == 'i') {AddCh(); goto case 45;}
+ else {t.kind = 124; break;}
case 97:
- recEnd = pos; recKind = 135;
- if (ch == '.') {AddCh(); goto case 47;}
- else {t.kind = 135; break;}
+ recEnd = pos; recKind = 139;
+ if (ch == '.') {AddCh(); goto case 48;}
+ else {t.kind = 139; break;}
case 98:
- recEnd = pos; recKind = 52;
- if (ch == '>') {AddCh(); goto case 75;}
- else {t.kind = 52; break;}
+ recEnd = pos; recKind = 54;
+ if (ch == '>') {AddCh(); goto case 76;}
+ else {t.kind = 54; break;}
case 99:
- recEnd = pos; recKind = 105;
+ recEnd = pos; recKind = 110;
if (ch == '=') {AddCh(); goto case 100;}
- else {t.kind = 105; break;}
+ else {t.kind = 110; break;}
case 100:
- recEnd = pos; recKind = 113;
- if (ch == '>') {AddCh(); goto case 73;}
- else {t.kind = 113; break;}
+ recEnd = pos; recKind = 118;
+ if (ch == '>') {AddCh(); goto case 74;}
+ else {t.kind = 118; break;}
}
t.val = new String(tval, 0, tlen);
@@ -973,6 +993,4 @@ public class Scanner {
} // end Scanner
public delegate void ErrorProc(int n, string filename, int line, int col);
-
-
} \ No newline at end of file
diff --git a/Source/Dafny/SccGraph.cs b/Source/Dafny/SccGraph.cs
index 01a72fc5..20b4f65e 100644
--- a/Source/Dafny/SccGraph.cs
+++ b/Source/Dafny/SccGraph.cs
@@ -6,8 +6,8 @@ namespace Microsoft.Dafny {
public class Graph<Node> where Node : class
{
- enum VisitedStatus { Unvisited, OnStack, Visited }
- class Vertex {
+ public enum VisitedStatus { Unvisited, OnStack, Visited }
+ public class Vertex {
public readonly Node N;
public readonly List<Vertex/*!*/>/*!*/ Successors = new List<Vertex/*!*/>();
public List<Vertex/*!*/> SccMembers; // non-null only for the representative of the SCC
@@ -65,6 +65,10 @@ namespace Microsoft.Dafny {
{
}
+ public IEnumerable<Vertex> GetVertices() {
+ return vertices.Values;
+ }
+
/// <summary>
/// Idempotently adds a vertex 'n' to the graph.
/// </summary>
@@ -97,7 +101,7 @@ namespace Microsoft.Dafny {
/// <summary>
/// Returns the vertex for 'n' if 'n' is in the graph. Otherwise, returns null.
/// </summary>
- Vertex FindVertex(Node n) {
+ public Vertex FindVertex(Node n) {
Vertex v;
if (vertices.TryGetValue(n, out v)) {
Contract.Assert(v != null); // follows from postcondition of TryGetValue (since 'vertices' maps to the type Vertex!)
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index 0e83f54a..99571a8c 100644
--- a/Source/Dafny/Translator.cs
+++ b/Source/Dafny/Translator.cs
@@ -93,9 +93,13 @@ namespace Microsoft.Dafny {
}
public class Translator {
+ ErrorReporter reporter;
+ // TODO(wuestholz): Enable this once Dafny's recommended Z3 version includes changeset 0592e765744497a089c42021990740f303901e67.
+ public bool UseOptimizationInZ3 { get; set; }
[NotDelayed]
- public Translator() {
+ public Translator(ErrorReporter reporter) {
+ this.reporter = reporter;
InsertChecksums = 0 < CommandLineOptions.Clo.VerifySnapshots;
Bpl.Program boogieProgram = ReadPrelude();
if (boogieProgram != null) {
@@ -109,11 +113,13 @@ namespace Microsoft.Dafny {
readonly Dictionary<TopLevelDecl, string>/*!*/ classConstants = new Dictionary<TopLevelDecl, string>();
readonly Dictionary<int, string> functionConstants = new Dictionary<int, string>();
readonly Dictionary<Function, string> functionHandles = new Dictionary<Function, string>();
+ readonly List<FuelConstant> functionFuel = new List<FuelConstant>();
readonly Dictionary<Field/*!*/,Bpl.Constant/*!*/>/*!*/ fields = new Dictionary<Field/*!*/,Bpl.Constant/*!*/>();
readonly Dictionary<Field/*!*/, Bpl.Function/*!*/>/*!*/ fieldFunctions = new Dictionary<Field/*!*/, Bpl.Function/*!*/>();
readonly Dictionary<string, Bpl.Constant> fieldConstants = new Dictionary<string,Constant>();
readonly ISet<string> abstractTypes = new HashSet<string>();
readonly ISet<string> opaqueTypes = new HashSet<string>();
+ FuelContext fuelContext = null;
Program program;
[ContractInvariantMethod]
@@ -137,6 +143,7 @@ namespace Microsoft.Dafny {
public readonly Bpl.Type BoxType;
public readonly Bpl.Type TickType;
private readonly Bpl.TypeSynonymDecl setTypeCtor;
+ private readonly Bpl.TypeSynonymDecl isetTypeCtor;
private readonly Bpl.TypeSynonymDecl multiSetTypeCtor;
private readonly Bpl.TypeCtorDecl mapTypeCtor;
private readonly Bpl.TypeCtorDecl imapTypeCtor;
@@ -183,12 +190,12 @@ namespace Microsoft.Dafny {
Contract.Invariant(allocField != null);
}
- public Bpl.Type SetType(IToken tok, Bpl.Type ty) {
+ public Bpl.Type SetType(IToken tok, bool finite, Bpl.Type ty) {
Contract.Requires(tok != null);
Contract.Requires(ty != null);
Contract.Ensures(Contract.Result<Bpl.Type>() != null);
- return new Bpl.TypeSynonymAnnotation(Token.NoToken, setTypeCtor, new List<Bpl.Type> { ty });
+ return new Bpl.TypeSynonymAnnotation(Token.NoToken, finite ? setTypeCtor : isetTypeCtor, new List<Bpl.Type> { ty });
}
public Bpl.Type MultiSetType(IToken tok, Bpl.Type ty) {
@@ -229,7 +236,7 @@ namespace Microsoft.Dafny {
}
public PredefinedDecls(Bpl.TypeCtorDecl charType, Bpl.TypeCtorDecl refType, Bpl.TypeCtorDecl boxType, Bpl.TypeCtorDecl tickType,
- Bpl.TypeSynonymDecl setTypeCtor, Bpl.TypeSynonymDecl multiSetTypeCtor,
+ Bpl.TypeSynonymDecl setTypeCtor, Bpl.TypeSynonymDecl isetTypeCtor, Bpl.TypeSynonymDecl multiSetTypeCtor,
Bpl.TypeCtorDecl mapTypeCtor, Bpl.TypeCtorDecl imapTypeCtor,
Bpl.Function arrayLength, Bpl.Function realTrunc, Bpl.TypeCtorDecl seqTypeCtor, Bpl.TypeCtorDecl fieldNameType,
Bpl.TypeCtorDecl tyType, Bpl.TypeCtorDecl tyTagType,
@@ -242,6 +249,7 @@ namespace Microsoft.Dafny {
Contract.Requires(boxType != null);
Contract.Requires(tickType != null);
Contract.Requires(setTypeCtor != null);
+ Contract.Requires(isetTypeCtor != null);
Contract.Requires(multiSetTypeCtor != null);
Contract.Requires(mapTypeCtor != null);
Contract.Requires(imapTypeCtor != null);
@@ -265,6 +273,7 @@ namespace Microsoft.Dafny {
this.BoxType = new Bpl.CtorType(Token.NoToken, boxType, new List<Bpl.Type>());
this.TickType = new Bpl.CtorType(Token.NoToken, tickType, new List<Bpl.Type>());
this.setTypeCtor = setTypeCtor;
+ this.isetTypeCtor = isetTypeCtor;
this.multiSetTypeCtor = multiSetTypeCtor;
this.mapTypeCtor = mapTypeCtor;
this.imapTypeCtor = imapTypeCtor;
@@ -298,6 +307,7 @@ namespace Microsoft.Dafny {
Bpl.TypeCtorDecl charType = null;
Bpl.TypeCtorDecl refType = null;
Bpl.TypeSynonymDecl setTypeCtor = null;
+ Bpl.TypeSynonymDecl isetTypeCtor = null;
Bpl.TypeSynonymDecl multiSetTypeCtor = null;
Bpl.Function arrayLength = null;
Bpl.Function realTrunc = null;
@@ -361,6 +371,9 @@ namespace Microsoft.Dafny {
if (dt.Name == "MultiSet") {
multiSetTypeCtor = dt;
}
+ if (dt.Name == "ISet") {
+ isetTypeCtor = dt;
+ }
} else if (d is Bpl.Constant) {
Bpl.Constant c = (Bpl.Constant)d;
if (c.Name == "alloc") {
@@ -384,6 +397,8 @@ namespace Microsoft.Dafny {
Console.WriteLine("Error: Dafny prelude is missing declaration of type Seq");
} else if (setTypeCtor == null) {
Console.WriteLine("Error: Dafny prelude is missing declaration of type Set");
+ } else if (isetTypeCtor == null) {
+ Console.WriteLine("Error: Dafny prelude is missing declaration of type ISet");
} else if (multiSetTypeCtor == null) {
Console.WriteLine("Error: Dafny prelude is missing declaration of type MultiSet");
} else if (mapTypeCtor == null) {
@@ -426,7 +441,7 @@ namespace Microsoft.Dafny {
Console.WriteLine("Error: Dafny prelude is missing declaration of constant alloc");
} else {
return new PredefinedDecls(charType, refType, boxType, tickType,
- setTypeCtor, multiSetTypeCtor,
+ setTypeCtor, isetTypeCtor, multiSetTypeCtor,
mapTypeCtor, imapTypeCtor,
arrayLength, realTrunc, seqTypeCtor, fieldNameType,
tyType, tyTagType,
@@ -474,6 +489,9 @@ namespace Microsoft.Dafny {
return new Bpl.Program();
}
+ // compute which function needs fuel constants.
+ ComputeFunctionFuel();
+
foreach (TopLevelDecl d in program.BuiltIns.SystemModule.TopLevelDecls) {
currentDeclaration = d;
if (d is OpaqueTypeDecl) {
@@ -563,6 +581,37 @@ namespace Microsoft.Dafny {
return sink;
}
+ private void ComputeFunctionFuel() {
+ foreach (ModuleDefinition m in program.Modules) {
+ foreach (TopLevelDecl d in m.TopLevelDecls) {
+ if (d is ClassDecl) {
+ ClassDecl c = (ClassDecl)d;
+ foreach (MemberDecl member in c.Members) {
+ if (member is Function) {
+ Function f = (Function)member;
+ // declare the fuel constant
+ if (f.IsFueled) {
+ // const BaseFuel_FunctionA : LayerType
+ Bpl.Constant baseFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, "BaseFuel_" + f.FullName, predef.LayerType), false);
+ sink.AddTopLevelDeclaration(baseFuel);
+ Bpl.Expr baseFuel_expr = new Bpl.IdentifierExpr(f.tok, baseFuel);
+ // const StartFuel_FunctionA : LayerType
+ Bpl.Constant startFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, "StartFuel_" + f.FullName, predef.LayerType), false);
+ sink.AddTopLevelDeclaration(startFuel);
+ Bpl.Expr startFuel_expr = new Bpl.IdentifierExpr(f.tok, startFuel);
+ // const StartFuelAssert_FunctionA : LayerType
+ Bpl.Constant startFuelAssert = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, "StartFuelAssert_" + f.FullName, predef.LayerType), false);
+ sink.AddTopLevelDeclaration(startFuelAssert);
+ Bpl.Expr startFuelAssert_expr = new Bpl.IdentifierExpr(f.tok, startFuelAssert);
+ this.functionFuel.Add(new FuelConstant(f, baseFuel_expr, startFuel_expr, startFuelAssert_expr));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/// <summary>
/// adding TraitParent axioms
/// if a class A extends trait J and B does not extend anything, then this method adds the followings to the sink:
@@ -616,6 +665,11 @@ namespace Microsoft.Dafny {
}
void AddTypeDecl(NewtypeDecl dd) {
Contract.Requires(dd != null);
+ Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));
+
+ FuelContext oldFuelContext = this.fuelContext;
+ this.fuelContext = FuelSetting.NewFuelContext(dd);
+
AddTypeDecl_Aux(dd.tok, dd.FullName, new List<TypeParameter>());
AddWellformednessCheck(dd);
// Add $Is and $IsAlloc axioms for the newtype
@@ -650,7 +704,8 @@ namespace Microsoft.Dafny {
ie.Var = oVarDafny; ie.Type = ie.Var.Type; // resolve ie here
var constraint = etran.TrExpr(Substitute(dd.Constraint, dd.Var, ie));
var heap = new Bpl.BoundVariable(dd.tok, new Bpl.TypedIdent(dd.tok, predef.HeapVarName, predef.HeapType));
- var ex = new Bpl.ExistsExpr(dd.tok, new List<Variable> { heap }, BplAnd(FunctionCall(dd.tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr), constraint));
+ //TRIG (exists $Heap: Heap :: $IsGoodHeap($Heap) && LitInt(0) <= $o#0 && $o#0 < 100)
+ var ex = new Bpl.ExistsExpr(dd.tok, new List<Variable> { heap }, BplAnd(FunctionCall(dd.tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr), constraint)); // LL_TRIGGER
rhs = BplAnd(rhs, ex);
}
body = BplIff(is_o, rhs);
@@ -658,6 +713,7 @@ namespace Microsoft.Dafny {
sink.AddTopLevelDeclaration(new Bpl.Axiom(dd.tok, BplForall(vars, BplTrigger(is_o), body), name));
});
+ this.fuelContext = oldFuelContext;
}
void AddTypeDecl_Aux(IToken tok, string nm, List<TypeParameter> typeArgs) {
Contract.Requires(tok != null);
@@ -689,8 +745,6 @@ namespace Microsoft.Dafny {
sink.AddTopLevelDeclaration(dt_const);
foreach (DatatypeCtor ctor in dt.Ctors) {
- int i;
-
// Add: function #dt.ctor(tyVars, paramTypes) returns (DatatypeType);
List<Bpl.Variable> argTypes = new List<Bpl.Variable>();
@@ -718,10 +772,11 @@ namespace Microsoft.Dafny {
{
// Add: axiom (forall params :: DatatypeCtorId(#dt.ctor(params)) == ##dt.ctor);
CreateBoundVariables(ctor.Formals, out bvs, out args);
- Bpl.Expr lhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- lhs = FunctionCall(ctor.tok, BuiltinFunction.DatatypeCtorId, null, lhs);
+ var constructor_call = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var lhs = FunctionCall(ctor.tok, BuiltinFunction.DatatypeCtorId, null, constructor_call);
Bpl.Expr q = Bpl.Expr.Eq(lhs, c);
- sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, BplForall(bvs, q), "Constructor identifier"));
+ var trigger = BplTrigger(constructor_call);
+ sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, BplForall(bvs, trigger, q), "Constructor identifier"));
}
{
@@ -747,14 +802,15 @@ namespace Microsoft.Dafny {
{
// Add: axiom (forall d: DatatypeType :: dt.ctor?(d) ==> (exists params :: d == #dt.ctor(params));
CreateBoundVariables(ctor.Formals, out bvs, out args);
- Bpl.Expr lhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
Bpl.Expr dId; var dBv = BplBoundVar("d", predef.DatatypeType, out dId);
- Bpl.Expr q = Bpl.Expr.Eq(dId, lhs);
+ Bpl.Expr q = Bpl.Expr.Eq(dId, rhs);
if (bvs.Count != 0) {
- q = new Bpl.ExistsExpr(ctor.tok, bvs, q);
+ q = new Bpl.ExistsExpr(ctor.tok, bvs, null/*always in a Skolemization context*/, q);
}
Bpl.Expr dtq = FunctionCall(ctor.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, dId);
- q = BplForall(dBv, null, BplImp(dtq, q));
+ var trigger = BplTrigger(dtq);
+ q = BplForall(dBv, trigger, BplImp(dtq, q));
sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Constructor questionmark has arguments"));
}
@@ -775,14 +831,13 @@ namespace Microsoft.Dafny {
Bpl.Expr h;
var hVar = BplBoundVar("$h", predef.HeapType, out h);
Bpl.Expr conj = Bpl.Expr.True;
- i = 0;
- foreach (Formal arg in ctor.Formals) {
+ for (var i = 0; i < ctor.Formals.Count; i++) {
+ var arg = ctor.Formals[i];
if (is_alloc) {
conj = BplAnd(conj, MkIsAlloc(args[i], arg.Type, h));
} else {
conj = BplAnd(conj, MkIs(args[i], arg.Type));
}
- i++;
}
var c_params = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
var c_ty = ClassTyCon((TopLevelDecl)dt, tyexprs);
@@ -818,8 +873,8 @@ namespace Microsoft.Dafny {
}
// Injectivity axioms for normal arguments
- i = 0;
- foreach (Formal arg in ctor.Formals) {
+ for (int i = 0; i < ctor.Formals.Count; i++) {
+ var arg = ctor.Formals[i];
// function ##dt.ctor#i(DatatypeType) returns (Ti);
var sf = ctor.Destructors[i];
Contract.Assert(sf != null);
@@ -835,75 +890,83 @@ namespace Microsoft.Dafny {
if (dt is IndDatatypeDecl) {
var argType = arg.Type.NormalizeExpand();
if (argType.IsDatatype || argType.IsTypeParameter) {
- // for datatype: axiom (forall params :: DtRank(params_i) < DtRank(#dt.ctor(params)));
- // for type-parameter type: axiom (forall params :: DtRank(Unbox(params_i)) < DtRank(#dt.ctor(params)));
+ // for datatype: axiom (forall params :: {#dt.ctor(params)} DtRank(params_i) < DtRank(#dt.ctor(params)));
+ // for type-parameter type: axiom (forall params :: {#dt.ctor(params)} BoxRank(params_i) < DtRank(#dt.ctor(params)));
CreateBoundVariables(ctor.Formals, out bvs, out args);
Bpl.Expr lhs = FunctionCall(ctor.tok, arg.Type.IsDatatype ? BuiltinFunction.DtRank : BuiltinFunction.BoxRank, null, args[i]);
/* CHECK
Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null,
argType.IsDatatype ? args[i] : FunctionCall(ctor.tok, BuiltinFunction.Unbox, predef.DatatypeType, args[i]));
- */
- Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
- q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Lt(lhs, rhs));
+ */
+ Bpl.Expr ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);
+ var trigger = BplTrigger(ct);
+ q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Lt(lhs, rhs));
sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Inductive rank"));
} else if (argType is SeqType) {
- // axiom (forall params, i: int :: 0 <= i && i < |arg| ==> DtRank(arg[i]) < DtRank(#dt.ctor(params)));
+ // axiom (forall params, i: int {#dt.ctor(params)} :: 0 <= i && i < |arg| ==> DtRank(arg[i]) < DtRank(#dt.ctor(params)));
// that is:
- // axiom (forall params, i: int :: 0 <= i && i < |arg| ==> DtRank(Unbox(Seq#Index(arg,i))) < DtRank(#dt.ctor(params)));
- CreateBoundVariables(ctor.Formals, out bvs, out args);
- Bpl.Variable iVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, "i", Bpl.Type.Int));
- bvs.Add(iVar);
- Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, iVar);
- Bpl.Expr ante = Bpl.Expr.And(
- Bpl.Expr.Le(Bpl.Expr.Literal(0), ie),
- Bpl.Expr.Lt(ie, FunctionCall(arg.tok, BuiltinFunction.SeqLength, null, args[i])));
- Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null,
- FunctionCall(arg.tok, BuiltinFunction.Unbox, predef.DatatypeType,
- FunctionCall(arg.tok, BuiltinFunction.SeqIndex, predef.DatatypeType, args[i], ie)));
- Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
- q = new Bpl.ForallExpr(ctor.tok, bvs, new Trigger(lhs.tok, true, new List<Bpl.Expr> { lhs, rhs }), Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
- sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q));
- // axiom (forall params, SeqRank(arg) < DtRank(#dt.ctor(params)));
- CreateBoundVariables(ctor.Formals, out bvs, out args);
- lhs = FunctionCall(ctor.tok, BuiltinFunction.SeqRank, null, args[i]);
- rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
- q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Lt(lhs, rhs));
- sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Inductive seq rank"));
+ // axiom (forall params, i: int {#dt.ctor(params)} :: 0 <= i && i < |arg| ==> DtRank(Unbox(Seq#Index(arg,i))) < DtRank(#dt.ctor(params)));
+ {
+ CreateBoundVariables(ctor.Formals, out bvs, out args);
+ Bpl.Variable iVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, "i", Bpl.Type.Int));
+ bvs.Add(iVar);
+ Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, iVar);
+ Bpl.Expr ante = Bpl.Expr.And(
+ Bpl.Expr.Le(Bpl.Expr.Literal(0), ie),
+ Bpl.Expr.Lt(ie, FunctionCall(arg.tok, BuiltinFunction.SeqLength, null, args[i])));
+ var seqIndex = FunctionCall(arg.tok, BuiltinFunction.SeqIndex, predef.DatatypeType, args[i], ie);
+ Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null,
+ FunctionCall(arg.tok, BuiltinFunction.Unbox, predef.DatatypeType, seqIndex));
+ var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);
+ q = new Bpl.ForallExpr(ctor.tok, bvs, new Trigger(lhs.tok, true, new List<Bpl.Expr> { seqIndex, ct }), Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
+ sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q));
+ }
+
+ // axiom (forall params {#dt.ctor(params)} :: SeqRank(arg) < DtRank(#dt.ctor(params)));
+ {
+ CreateBoundVariables(ctor.Formals, out bvs, out args);
+ var lhs = FunctionCall(ctor.tok, BuiltinFunction.SeqRank, null, args[i]);
+ var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);
+ var trigger = BplTrigger(ct);
+ q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Lt(lhs, rhs));
+ sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Inductive seq rank"));
+ }
} else if (argType is SetType) {
- // axiom (forall params, d: Datatype :: arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ // axiom (forall params, d: Datatype {arg[d], #dt.ctor(params)} :: arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));
// that is:
- // axiom (forall params, d: Datatype :: arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ // axiom (forall params, d: Datatype {arg[Box(d)], #dt.ctor(params)} :: arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));
CreateBoundVariables(ctor.Formals, out bvs, out args);
Bpl.Variable dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, "d", predef.DatatypeType));
bvs.Add(dVar);
Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, dVar);
- Bpl.Expr ante = Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));
+ Bpl.Expr inSet = Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));
Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);
- Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
- q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
+ var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);
+ var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inSet, ct });
+ q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(inSet, Bpl.Expr.Lt(lhs, rhs)));
sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Inductive set rank"));
} else if (argType is MultiSetType) {
- // axiom (forall params, d: Datatype :: 0 < arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ // axiom (forall params, d: Datatype {arg[d], #dt.ctor(params)} :: 0 < arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));
// that is:
- // axiom (forall params, d: Datatype :: 0 < arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));
+ // axiom (forall params, d: Datatype {arg[Box(d)], #dt.ctor(params)} :: 0 < arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));
CreateBoundVariables(ctor.Formals, out bvs, out args);
Bpl.Variable dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, "d", predef.DatatypeType));
bvs.Add(dVar);
Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, dVar);
- Bpl.Expr ante = Bpl.Expr.Gt(Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie)), Bpl.Expr.Literal(0));
+ var inMultiset = Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));
+ Bpl.Expr ante = Bpl.Expr.Gt(inMultiset, Bpl.Expr.Literal(0));
Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);
- Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
- rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, rhs);
- q = new Bpl.ForallExpr(ctor.tok, bvs, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
+ var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);
+ var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);
+ var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inMultiset, ct });
+ q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));
sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, "Inductive multiset rank"));
}
}
-
- i++;
}
}
@@ -1103,9 +1166,9 @@ namespace Microsoft.Dafny {
CoAxHelper(true, (tyargs, vars, lexprs, rexprs, kVar, k, kGtZero, ly, d0, d1) => {
var equal = Bpl.Expr.Eq(d0, d1);
var PEq = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);
+ var trigger = BplTrigger(PEq);
sink.AddTopLevelDeclaration(new Axiom(dt.tok,
- BplForall(vars, null, BplImp(BplAnd(equal, kGtZero), PEq)),
- "Prefix equality shortcut"));
+ BplForall(vars, trigger, BplImp(BplAnd(equal, kGtZero), PEq)), "Prefix equality shortcut"));
});
}
}
@@ -1172,7 +1235,7 @@ namespace Microsoft.Dafny {
}
}
- Bpl.Expr LayerSucc(Bpl.Expr e, int amt = 1) {
+ public Bpl.Expr LayerSucc(Bpl.Expr e, int amt = 1) {
if (amt == 0) {
return e;
} else if (amt > 0) {
@@ -1292,6 +1355,7 @@ namespace Microsoft.Dafny {
{
Contract.Requires(sink != null && predef != null);
Contract.Requires(c != null);
+ Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));
sink.AddTopLevelDeclaration(GetClass(c));
if (c is ArrayClassDecl) {
@@ -1378,6 +1442,9 @@ namespace Microsoft.Dafny {
} else if (member is Function) {
var f = (Function)member;
+ FuelContext oldFuelContext = this.fuelContext;
+ this.fuelContext = FuelSetting.NewFuelContext(f);
+
AddClassMember_Function(f);
if (!IsOpaqueFunction(f) && !f.IsBuiltin && !(f.tok is IncludeToken)) { // Opaque function's well-formedness is checked on the full version
AddWellformednessCheck(f);
@@ -1390,9 +1457,11 @@ namespace Microsoft.Dafny {
AddClassMember_Function(cop.PrefixPredicate);
// skip the well-formedness check, because it has already been done for the fixpoint-predicate
}
-
+ this.fuelContext = oldFuelContext;
} else if (member is Method) {
Method m = (Method)member;
+ FuelContext oldFuelContext = this.fuelContext;
+ this.fuelContext = FuelSetting.NewFuelContext(m);
// wellformedness check for method specification
if (m.EnclosingClass is IteratorDecl && m == ((IteratorDecl)m.EnclosingClass).Member_MoveNext) {
@@ -1425,7 +1494,7 @@ namespace Microsoft.Dafny {
sink.AddTopLevelDeclaration(proc);
AddMethodImpl(m, proc, false);
}
-
+ this.fuelContext = oldFuelContext;
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member
}
@@ -1434,13 +1503,15 @@ namespace Microsoft.Dafny {
/// <summary>
/// Returns true if the body of function "f" is available in module "context".
- /// This happens when "f" has a body, "f" is not opaque, and either "f" is declared
- /// in module "context" or "f" is not protected.
+ /// This happens when the following conditions all hold:
+ /// - "f" has a body
+ /// - "f" is not opaque
+ /// - "f" is declared as protected, then "context" is the current module and parameter "revealProtectedBody" is passed in as "true".
/// </summary>
- static bool FunctionBodyIsAvailable(Function f, ModuleDefinition context) {
+ static bool FunctionBodyIsAvailable(Function f, ModuleDefinition context, bool revealProtectedBody) {
Contract.Requires(f != null);
Contract.Requires(context != null);
- return f.Body != null && !IsOpaqueFunction(f) && (f.EnclosingClass.Module == context || !f.IsProtected);
+ return f.Body != null && !IsOpaqueFunction(f) && (!f.IsProtected || (revealProtectedBody && f.EnclosingClass.Module == context));
}
static bool IsOpaqueFunction(Function f) {
Contract.Requires(f != null);
@@ -1458,7 +1529,7 @@ namespace Microsoft.Dafny {
// declare function
AddFunction(f);
// add synonym axiom
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
AddSynonymAxiom(f);
}
// add frame axiom
@@ -1471,7 +1542,7 @@ namespace Microsoft.Dafny {
AddFunctionAxiom(f, FunctionAxiomVisibility.ForeignModuleOnly, f.Body.Resolved);
}
// for body-less functions, at least generate its #requires function
- if (f.Body == null) {
+ if (f.Body == null || IsOpaqueFunction(f)) {
var b = FunctionAxiom(f, FunctionAxiomVisibility.ForeignModuleOnly, null, null);
Contract.Assert(b == null);
}
@@ -1485,6 +1556,10 @@ namespace Microsoft.Dafny {
void AddIteratorSpecAndBody(IteratorDecl iter) {
Contract.Requires(iter != null);
+ Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));
+
+ FuelContext oldFuelContext = this.fuelContext;
+ this.fuelContext = FuelSetting.NewFuelContext(iter);
// wellformedness check for method specification
Bpl.Procedure proc = AddIteratorProc(iter, MethodTranslationKind.SpecWellformedness);
@@ -1497,6 +1572,7 @@ namespace Microsoft.Dafny {
// ...and its implementation
AddIteratorImpl(iter, proc);
}
+ this.fuelContext = oldFuelContext;
}
Bpl.Procedure AddIteratorProc(IteratorDecl iter, MethodTranslationKind kind) {
@@ -1534,8 +1610,7 @@ namespace Microsoft.Dafny {
req.Add(Requires(p.E.tok, true, etran.TrExpr(p.E), null, comment));
comment = null;
} else {
- bool splitHappened; // we actually don't care
- foreach (var s in TrSplitExpr(p.E, etran, kind == MethodTranslationKind.InterModuleCall ? 0 : int.MaxValue, true, out splitHappened)) {
+ foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {
if (kind == MethodTranslationKind.IntraModuleCall && RefinementToken.IsInherited(s.E.tok, currentModule)) {
// this precondition was inherited into this module, so just ignore it
} else {
@@ -1552,8 +1627,7 @@ namespace Microsoft.Dafny {
ens.Add(Ensures(p.E.tok, true, etran.TrExpr(p.E), null, comment));
comment = null;
} else {
- bool splitHappened; // we actually don't care
- foreach (var s in TrSplitExpr(p.E, etran, kind == MethodTranslationKind.InterModuleCall ? 0 : int.MaxValue, true, out splitHappened)) {
+ foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {
if (kind == MethodTranslationKind.Implementation && RefinementToken.IsInherited(s.E.tok, currentModule)) {
// this postcondition was inherited into this module, so just ignore it
} else {
@@ -1599,8 +1673,7 @@ namespace Microsoft.Dafny {
Bpl.StmtList stmts;
// check well-formedness of the preconditions, and then assume each one of them
foreach (var p in iter.Requires) {
- CheckWellformed(p.E, new WFOptions(), localVariables, builder, etran);
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);
}
// check well-formedness of the modifies and reads clauses
CheckFrameWellFormed(new WFOptions(), iter.Modifies.Expressions, localVariables, builder, etran);
@@ -1612,7 +1685,7 @@ namespace Microsoft.Dafny {
// Next, we assume about this.* whatever we said that the iterator constructor promises
foreach (var p in iter.Member_Init.Ens) {
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));
}
// play havoc with the heap, except at the locations prescribed by (this._reads - this._modifies - {this})
@@ -1638,12 +1711,11 @@ namespace Microsoft.Dafny {
validCall.TypeArgumentSubstitutions[p] = new UserDefinedType(p);
} // resolved here.
- builder.Add(new Bpl.AssumeCmd(iter.tok, etran.TrExpr(validCall)));
+ builder.Add(TrAssumeCmd(iter.tok, etran.TrExpr(validCall)));
// check well-formedness of the user-defined part of the yield-requires
foreach (var p in iter.YieldRequires) {
- CheckWellformed(p.E, new WFOptions(), localVariables, builder, etran);
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);
}
// save the heap (representing the state where yield-requires holds): $_OldIterHeap := Heap;
@@ -1666,13 +1738,13 @@ namespace Microsoft.Dafny {
setDiff.ResolvedOp = BinaryExpr.ResolvedOpcode.SetDifference; setDiff.Type = nw.Type; // resolve here
Expression cond = new UnaryOpExpr(iter.tok, UnaryOpExpr.Opcode.Fresh, setDiff);
cond.Type = Type.Bool; // resolve here
- builder.Add(new Bpl.AssumeCmd(iter.tok, yeEtran.TrExpr(cond)));
+ builder.Add(TrAssumeCmd(iter.tok, yeEtran.TrExpr(cond)));
// check wellformedness of postconditions
var yeBuilder = new Bpl.StmtListBuilder();
var endBuilder = new Bpl.StmtListBuilder();
// In the yield-ensures case: assume this.Valid();
- yeBuilder.Add(new Bpl.AssumeCmd(iter.tok, yeEtran.TrExpr(validCall)));
+ yeBuilder.Add(TrAssumeCmd(iter.tok, yeEtran.TrExpr(validCall)));
Contract.Assert(iter.OutsFields.Count == iter.OutsHistoryFields.Count);
for (int i = 0; i < iter.OutsFields.Count; i++) {
var y = iter.OutsFields[i];
@@ -1689,18 +1761,16 @@ namespace Microsoft.Dafny {
concat.ResolvedOp = BinaryExpr.ResolvedOpcode.Concat; concat.Type = oldThisYs.Type; // resolve here
// In the yield-ensures case: assume this.ys == old(this.ys) + [this.y];
- yeBuilder.Add(new Bpl.AssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(concat))));
+ yeBuilder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(concat))));
// In the ensures case: assume this.ys == old(this.ys);
- endBuilder.Add(new Bpl.AssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(oldThisYs))));
+ endBuilder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(oldThisYs))));
}
foreach (var p in iter.YieldEnsures) {
- CheckWellformed(p.E, new WFOptions(), localVariables, yeBuilder, yeEtran);
- yeBuilder.Add(new Bpl.AssumeCmd(p.E.tok, yeEtran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, yeBuilder, yeEtran);
}
foreach (var p in iter.Ensures) {
- CheckWellformed(p.E, new WFOptions(), localVariables, endBuilder, yeEtran);
- endBuilder.Add(new Bpl.AssumeCmd(p.E.tok, yeEtran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, endBuilder, yeEtran);
}
builder.Add(new Bpl.IfCmd(iter.tok, null, yeBuilder.Collect(iter.tok), null, endBuilder.Collect(iter.tok)));
@@ -1740,23 +1810,23 @@ namespace Microsoft.Dafny {
// add locals for the yield-history variables and the extra variables
// Assume the precondition and postconditions of the iterator constructor method
foreach (var p in iter.Member_Init.Req) {
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));
}
foreach (var p in iter.Member_Init.Ens) {
// these postconditions are two-state predicates, but that's okay, because we haven't changed anything yet
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));
}
// add the _yieldCount variable, and assume its initial value to be 0
yieldCountVariable = new Bpl.LocalVariable(iter.tok,
new Bpl.TypedIdent(iter.tok, iter.YieldCountVariable.AssignUniqueName(currentDeclaration.IdGenerator), TrType(iter.YieldCountVariable.Type)));
yieldCountVariable.TypedIdent.WhereExpr = YieldCountAssumption(iter, etran); // by doing this after setting "yieldCountVariable", the variable can be used by YieldCountAssumption
localVariables.Add(yieldCountVariable);
- builder.Add(new Bpl.AssumeCmd(iter.tok, Bpl.Expr.Eq(new Bpl.IdentifierExpr(iter.tok, yieldCountVariable), Bpl.Expr.Literal(0))));
+ builder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(new Bpl.IdentifierExpr(iter.tok, yieldCountVariable), Bpl.Expr.Literal(0))));
// add a variable $_OldIterHeap
var oih = new Bpl.IdentifierExpr(iter.tok, "$_OldIterHeap", predef.HeapType);
Bpl.Expr wh = BplAnd(
FunctionCall(iter.tok, BuiltinFunction.IsGoodHeap, null, oih),
- FunctionCall(iter.tok, BuiltinFunction.HeapSucc, null, oih, etran.HeapExpr));
+ HeapSucc(oih, etran.HeapExpr));
localVariables.Add(new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, "$_OldIterHeap", predef.HeapType, wh)));
// do an initial YieldHavoc
@@ -1877,10 +1947,8 @@ namespace Microsoft.Dafny {
// danr: Let's create the literal function axioms if there is an arrow type in the signature
if (!(f is FixpointPredicate) && (f.Reads.Count == 0 || f.Formals.Exists(a => a.Type.IsArrowType))) {
var FVs = new HashSet<IVariable>();
- bool usesHeap = false, usesOldHeap = false;
- Type usesThis = null;
foreach (var e in f.Decreases.Expressions) {
- ComputeFreeVariables(e, FVs, ref usesHeap, ref usesOldHeap, ref usesThis, false);
+ ComputeFreeVariables(e, FVs);
}
var decs = new List<Formal>();
foreach (var formal in f.Formals) {
@@ -1947,7 +2015,7 @@ namespace Microsoft.Dafny {
var formals = MkTyParamBinders(GetTypeParams(f), out tyargs);
var args = new List<Bpl.Expr>();
Bpl.BoundVariable layer;
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
layer = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType));
formals.Add(layer);
// Note, "layer" is not added to "args" here; rather, that's done below, as needed
@@ -2014,15 +2082,15 @@ namespace Microsoft.Dafny {
Bpl.Trigger tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { funcAppl });
var typeParams = TrTypeParamDecls(f.TypeArgs);
- Bpl.Expr meat = Bpl.Expr.True;
+ Bpl.Expr post = Bpl.Expr.True;
foreach (Expression p in ens) {
Bpl.Expr q = etran.TrExpr(Substitute(p, null, substMap));
- meat = BplAnd(meat, q);
+ post = BplAnd(post, q);
}
Bpl.Expr whr = GetWhereClause(f.tok, funcAppl, f.ResultType, etran);
- if (whr != null) { meat = Bpl.Expr.And(meat, whr); }
+ if (whr != null) { post = Bpl.Expr.And(post, whr); }
- Bpl.Expr ax = new Bpl.ForallExpr(f.tok, typeParams, formals, null, tr, Bpl.Expr.Imp(ante, meat));
+ Bpl.Expr ax = new Bpl.ForallExpr(f.tok, typeParams, formals, null, tr, Bpl.Expr.Imp(ante, post));
var activate = AxiomActivation(f, true, true, etran);
string comment = "consequence axiom for " + f.FullSanitizedName;
return new Bpl.Axiom(f.tok, Bpl.Expr.Imp(activate, ax), comment);
@@ -2118,7 +2186,7 @@ namespace Microsoft.Dafny {
var formals = MkTyParamBinders(GetTypeParams(f), out tyargs);
Bpl.BoundVariable layer;
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
layer = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType));
formals.Add(layer);
// Note, "layer" is not added to "args" here; rather, that's done below, as needed
@@ -2173,13 +2241,6 @@ namespace Microsoft.Dafny {
foreach (Expression req in f.Req) {
pre = BplAnd(pre, etran.TrExpr(Substitute(req, null, substMap)));
}
- // useViaContext: (mh != ModuleContextHeight || fh != FunctionContextHeight)
- ModuleDefinition mod = f.EnclosingClass.Module;
- Bpl.Expr useViaContext = visibility == FunctionAxiomVisibility.ForeignModuleOnly ? (Bpl.Expr)Bpl.Expr.True :
- Bpl.Expr.Neq(Bpl.Expr.Literal(mod.CallGraph.GetSCCRepresentativeId(f)), etran.FunctionContextHeight());
-
- // ante := (useViaContext && typeAnte && pre)
- ante = BplAnd(useViaContext, BplAnd(ante, pre));
// Add the precondition function and its axiom (which is equivalent to the ante)
if (body == null || (visibility == FunctionAxiomVisibility.IntraModuleOnly && lits == null)) {
@@ -2192,14 +2253,21 @@ namespace Microsoft.Dafny {
}
var appl = FunctionCall(f.tok, RequiresName(f), Bpl.Type.Bool,
formals.ConvertAll(x => (Bpl.Expr)(new Bpl.IdentifierExpr(f.tok, x))));
- sink.AddTopLevelDeclaration(new Axiom(f.tok, BplForall(formals, BplTrigger(appl), Bpl.Expr.Eq(appl, ante))));
- // you could use it to check that it always works, but it makes VSI-Benchmarks/b3.dfy time out:
- // ante = appl;
+ // axiom (forall params :: { f#requires(params) } ante ==> f#requires(params) == pre);
+ sink.AddTopLevelDeclaration(new Axiom(f.tok, BplForall(formals, BplTrigger(appl),
+ BplImp(ante, Bpl.Expr.Eq(appl, pre)))));
if (body == null) {
return null;
}
}
+ // useViaContext: (mh != ModuleContextHeight || fh != FunctionContextHeight)
+ ModuleDefinition mod = f.EnclosingClass.Module;
+ Bpl.Expr useViaContext = visibility == FunctionAxiomVisibility.ForeignModuleOnly ? (Bpl.Expr)Bpl.Expr.True :
+ Bpl.Expr.Neq(Bpl.Expr.Literal(mod.CallGraph.GetSCCRepresentativeId(f)), etran.FunctionContextHeight());
+ // ante := (useViaContext && typeAnte && pre)
+ ante = BplAnd(useViaContext, BplAnd(ante, pre));
+
// useViaCanCall: f#canCall(args)
Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName + "#canCall", Bpl.Type.Bool);
Bpl.Expr useViaCanCall = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(canCallFuncID), Concat(tyargs,args));
@@ -2230,9 +2298,9 @@ namespace Microsoft.Dafny {
Bpl.Trigger tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { funcAppl });
var typeParams = TrTypeParamDecls(f.TypeArgs);
- Bpl.Expr meat;
+ Bpl.Expr tastyVegetarianOption;
if (visibility == FunctionAxiomVisibility.ForeignModuleOnly && f.IsProtected) {
- meat = Bpl.Expr.True;
+ tastyVegetarianOption = Bpl.Expr.True;
} else {
var bodyWithSubst = Substitute(body, null, substMap);
if (f is PrefixPredicate) {
@@ -2240,14 +2308,14 @@ namespace Microsoft.Dafny {
bodyWithSubst = PrefixSubstitution(pp, bodyWithSubst);
}
var etranBody = layer == null ? etran : etran.LimitedFunctions(f, new Bpl.IdentifierExpr(f.tok, layer));
- meat = BplAnd(CanCallAssumption(bodyWithSubst, etranBody),
+ tastyVegetarianOption = BplAnd(CanCallAssumption(bodyWithSubst, etranBody),
Bpl.Expr.Eq(funcAppl, etranBody.TrExpr(bodyWithSubst)));
}
QKeyValue kv = null;
if (lits != null) {
kv = new QKeyValue(f.tok, "weight", new List<object>() { Bpl.Expr.Literal(3) }, null);
}
- Bpl.Expr ax = new Bpl.ForallExpr(f.tok, typeParams, formals, kv, tr, Bpl.Expr.Imp(ante, meat));
+ Bpl.Expr ax = new Bpl.ForallExpr(f.tok, typeParams, formals, kv, tr, Bpl.Expr.Imp(ante, tastyVegetarianOption));
var activate = AxiomActivation(f, visibility == FunctionAxiomVisibility.ForeignModuleOnly, visibility == FunctionAxiomVisibility.IntraModuleOnly, etran);
string comment;
if (overridingClass == null) {
@@ -2314,7 +2382,7 @@ namespace Microsoft.Dafny {
void AddSynonymAxiom(Function f) {
Contract.Requires(f != null);
- Contract.Requires(f.IsRecursive);
+ Contract.Requires(f.IsFuelAware());
Contract.Requires(sink != null && predef != null);
// axiom // layer synonym axiom
// (forall s, $Heap, formals ::
@@ -2397,7 +2465,7 @@ namespace Microsoft.Dafny {
var coArgs = new List<Bpl.Expr>(tyexprs);
var prefixArgs = new List<Bpl.Expr>(tyexprs);
var prefixArgsLimited = new List<Bpl.Expr>(tyexprs);
- if (pp.IsRecursive) {
+ if (pp.IsFuelAware()) {
var sV = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, "$ly", predef.LayerType));
var s = new Bpl.IdentifierExpr(tok, sV);
var succS = FunctionCall(tok, BuiltinFunction.LayerSucc, null, s);
@@ -2486,11 +2554,11 @@ namespace Microsoft.Dafny {
moreBvs.Add(k);
var z = Bpl.Expr.Eq(kId, Bpl.Expr.Literal(0));
funcID = new Bpl.IdentifierExpr(tok, pp.FullSanitizedName, TrType(pp.ResultType));
- Bpl.Expr prefixLimited = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimited);
- if (pp.FixpointPred is InductivePredicate) {
- prefixLimited = Bpl.Expr.Not(prefixLimited);
- }
- var trueAtZero = new Bpl.ForallExpr(tok, moreBvs, BplImp(BplAnd(ante, z), prefixLimited));
+ Bpl.Expr prefixLimitedBody = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimited);
+ Bpl.Expr prefixLimited = pp.FixpointPred is InductivePredicate ? Bpl.Expr.Not(prefixLimitedBody) : prefixLimitedBody;
+
+ var trigger = BplTrigger(prefixLimitedBody);
+ var trueAtZero = new Bpl.ForallExpr(tok, moreBvs, trigger, BplImp(BplAnd(ante, z), prefixLimited));
sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, trueAtZero),
"3rd prefix predicate axiom"));
}
@@ -2505,7 +2573,6 @@ namespace Microsoft.Dafny {
/// ($IsAlloc(o, TClassA(G), h) // or h[o, alloc]
/// ==> $IsAlloc(h[o, f], TT(PP), h))
/// && $Is(h[o, f], TT(PP), h);
- /// <summary>
/// This can be optimised later to:
/// axiom (forall o: ref, h: Heap ::
/// { h[o, f] }
@@ -2513,6 +2580,7 @@ namespace Microsoft.Dafny {
/// ==>
/// (h[o, alloc] ==> $IsAlloc(h[o, f], TT(TClassA_Inv_i(dtype(o)),..), h))
/// && $Is(h[o, f], TT(TClassA_Inv_i(dtype(o)),..), h);
+ /// <summary>
void AddAllocationAxiom(Field f, ClassDecl c, bool is_array = false)
{
// IFF you're adding the array axioms, then the field should be null
@@ -2547,12 +2615,7 @@ namespace Microsoft.Dafny {
var tyvars = MkTyParamBinders(GetTypeParams(c), out tyexprs);
Bpl.Expr o_ty = ClassTyCon(c, tyexprs);
-
- // Bpl.Expr is_o = MkIs(o, o_ty); // $Is(o, ..)
- // Changed to use dtype(o) == o_ty instead:
- Bpl.Expr is_o = DType(o, o_ty);
- // Bpl.Expr isalloc_o = MkIsAlloc(o, o_ty, h); // $IsAlloc(o, ..)
- // Changed to use h[o,alloc] instead:
+ Bpl.Expr is_o = c is TraitDecl ? MkIs(o, o_ty) : DType(o, o_ty); // $Is(o, ..) or dtype(o) == o_ty
Bpl.Expr isalloc_o = IsAlloced(c.tok, h, o);
Bpl.Expr is_hf, isalloc_hf;
@@ -2727,131 +2790,118 @@ namespace Microsoft.Dafny {
Bpl.StmtListBuilder builder = new Bpl.StmtListBuilder();
builder.Add(new CommentCmd("AddMethodImpl: " + m + ", " + proc));
ExpressionTranslator etran = new ExpressionTranslator(this, predef, m.tok);
+ InitializeFuelConstant(m.tok, builder, etran);
List<Variable> localVariables = new List<Variable>();
GenerateImplPrelude(m, wellformednessProc, inParams, outParams, builder, localVariables);
+ if (UseOptimizationInZ3 && m.Ins != null)
+ {
+ // We ask Z3 to minimize all parameters of type 'nat'.
+ foreach (var f in m.Ins)
+ {
+ if (f.Type is NatType)
+ {
+ builder.Add(optimizeExpr(true, new IdentifierExpr(f), f.Tok, etran));
+ }
+ }
+ }
+
Bpl.StmtList stmts;
if (!wellformednessProc) {
- if (3 <= DafnyOptions.O.Induction && m.IsGhost && m.Mod.Expressions.Count == 0 && m.Outs.Count == 0 && !(m is FixpointLemma)) {
- var posts = new List<Expression>();
- m.Ens.ForEach(mfe => posts.Add(mfe.E));
- var allIns = new List<Formal>();
- if (!m.IsStatic) {
- allIns.Add(new ThisSurrogate(m.tok, Resolver.GetThisType(m.tok, (ClassDecl)m.EnclosingClass)));
- }
- allIns.AddRange(m.Ins);
- var inductionVars = ApplyInduction(allIns, m.Attributes, posts, delegate(System.IO.TextWriter wr) { wr.Write(m.FullName); });
- if (inductionVars.Count != 0) {
- // Let the parameters be this,x,y of the method M and suppose ApplyInduction returns this,y.
- // Also, let Pre be the precondition and VF be the decreases clause.
- // Then, insert into the method body what amounts to:
- // assume case-analysis-on-parameter[[ y' ]];
- // forall (this', y' | Pre(this', x, y') && VF(this', x, y') << VF(this, x, y)) {
- // this'.M(x, y');
- // }
- // Generate bound variables for the forall statement, and a substitution for the Pre and VF
-
- // assume case-analysis-on-parameter[[ y' ]];
- foreach (var inFormal in m.Ins) {
- var dt = inFormal.Type.AsDatatype;
- if (dt != null) {
- var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(inFormal.tok, "$IsA#" + dt.FullSanitizedName, Bpl.Type.Bool));
- var f = new Bpl.IdentifierExpr(inFormal.tok, inFormal.AssignUniqueName(m.IdGenerator), TrType(inFormal.Type));
- builder.Add(new Bpl.AssumeCmd(inFormal.tok, new Bpl.NAryExpr(inFormal.tok, funcID, new List<Bpl.Expr> { f })));
- }
- }
-
- var parBoundVars = new List<BoundVar>();
- Expression receiverReplacement = null;
- var substMap = new Dictionary<IVariable, Expression>();
- foreach (var iv in inductionVars) {
- BoundVar bv;
- IdentifierExpr ie;
- CloneVariableAsBoundVar(iv.tok, iv, "$ih#" + iv.Name, out bv, out ie);
- parBoundVars.Add(bv);
- if (iv is ThisSurrogate) {
- Contract.Assert(receiverReplacement == null && substMap.Count == 0); // the receiver comes first, if at all
- receiverReplacement = ie;
- } else {
- substMap.Add(iv, ie);
- }
- }
+ var inductionVars = ApplyInduction(m.Ins, m.Attributes);
+ if (inductionVars.Count != 0) {
+ // Let the parameters be this,x,y of the method M and suppose ApplyInduction returns y.
+ // Also, let Pre be the precondition and VF be the decreases clause.
+ // Then, insert into the method body what amounts to:
+ // assume case-analysis-on-parameter[[ y' ]];
+ // forall (y' | Pre(this, x, y') && VF(this, x, y') << VF(this, x, y)) {
+ // this.M(x, y');
+ // }
+ // Generate bound variables for the forall statement, and a substitution for the Pre and VF
+
+ // assume case-analysis-on-parameter[[ y' ]];
+ foreach (var inFormal in m.Ins) {
+ var dt = inFormal.Type.AsDatatype;
+ if (dt != null) {
+ var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(inFormal.tok, "$IsA#" + dt.FullSanitizedName, Bpl.Type.Bool));
+ var f = new Bpl.IdentifierExpr(inFormal.tok, inFormal.AssignUniqueName(m.IdGenerator), TrType(inFormal.Type));
+ builder.Add(TrAssumeCmd(inFormal.tok, new Bpl.NAryExpr(inFormal.tok, funcID, new List<Bpl.Expr> { f })));
+ }
+ }
+
+ var parBoundVars = new List<BoundVar>();
+ var substMap = new Dictionary<IVariable, Expression>();
+ foreach (var iv in inductionVars) {
+ BoundVar bv;
+ IdentifierExpr ie;
+ CloneVariableAsBoundVar(iv.tok, iv, "$ih#" + iv.Name, out bv, out ie);
+ parBoundVars.Add(bv);
+ substMap.Add(iv, ie);
+ }
- // Generate a CallStmt for the recursive call
- Expression recursiveCallReceiver;
- if (receiverReplacement != null) {
- recursiveCallReceiver = receiverReplacement;
- } else if (m.IsStatic) {
- recursiveCallReceiver = new StaticReceiverExpr(m.tok, (ClassDecl)m.EnclosingClass); // this also resolves it
+ // Generate a CallStmt for the recursive call
+ Expression recursiveCallReceiver;
+ if (m.IsStatic) {
+ recursiveCallReceiver = new StaticReceiverExpr(m.tok, (ClassDecl)m.EnclosingClass, true); // this also resolves it
+ } else {
+ recursiveCallReceiver = new ImplicitThisExpr(m.tok);
+ recursiveCallReceiver.Type = Resolver.GetThisType(m.tok, (ClassDecl)m.EnclosingClass); // resolve here
+ }
+ var recursiveCallArgs = new List<Expression>();
+ foreach (var inFormal in m.Ins) {
+ Expression inE;
+ if (substMap.TryGetValue(inFormal, out inE)) {
+ recursiveCallArgs.Add(inE);
} else {
- recursiveCallReceiver = new ImplicitThisExpr(m.tok);
- recursiveCallReceiver.Type = Resolver.GetThisType(m.tok, (ClassDecl)m.EnclosingClass); // resolve here
- }
- var recursiveCallArgs = new List<Expression>();
- foreach (var inFormal in m.Ins) {
- Expression inE;
- if (substMap.TryGetValue(inFormal, out inE)) {
- recursiveCallArgs.Add(inE);
- } else {
- var ie = new IdentifierExpr(inFormal.tok, inFormal.Name);
- ie.Var = inFormal; // resolve here
- ie.Type = inFormal.Type; // resolve here
- recursiveCallArgs.Add(ie);
- }
- }
- var methodSel = new MemberSelectExpr(m.tok, recursiveCallReceiver, m.Name);
- methodSel.Member = m; // resolve here
- methodSel.TypeApplication = new List<Type>();
- methodSel.TypeApplication.AddRange(recursiveCallReceiver.Type.TypeArgs);
- m.TypeArgs.ForEach(tp => methodSel.TypeApplication.Add(new UserDefinedType(tp)));
- methodSel.Type = new InferredTypeProxy(); // this is the last step in resolving 'methodSel'
- var recursiveCall = new CallStmt(m.tok, m.tok, new List<Expression>(), methodSel, recursiveCallArgs);
- recursiveCall.IsGhost = m.IsGhost; // resolve here
-
- Expression parRange = new LiteralExpr(m.tok, true);
- parRange.Type = Type.Bool; // resolve here
- if (receiverReplacement != null) {
- // add "this' != null" to the range
- var nil = new LiteralExpr(receiverReplacement.tok);
- nil.Type = receiverReplacement.Type; // resolve here
- var neqNull = new BinaryExpr(receiverReplacement.tok, BinaryExpr.Opcode.Neq, receiverReplacement, nil);
- neqNull.ResolvedOp = BinaryExpr.ResolvedOpcode.NeqCommon; // resolve here
- neqNull.Type = Type.Bool; // resolve here
- parRange = Expression.CreateAnd(parRange, neqNull);
- }
- foreach (var pre in m.Req) {
- if (!pre.IsFree) {
- parRange = Expression.CreateAnd(parRange, Substitute(pre.E, receiverReplacement, substMap));
- }
- }
- // construct an expression (generator) for: VF' << VF
- ExpressionConverter decrCheck = delegate(Dictionary<IVariable, Expression> decrSubstMap, ExpressionTranslator exprTran) {
- var decrToks = new List<IToken>();
- var decrTypes = new List<Type>();
- var decrCallee = new List<Expr>();
- var decrCaller = new List<Expr>();
- foreach (var ee in m.Decreases.Expressions) {
- decrToks.Add(ee.tok);
- decrTypes.Add(ee.Type.NormalizeExpand());
- decrCaller.Add(exprTran.TrExpr(ee));
- Expression es = Substitute(ee, receiverReplacement, substMap);
- es = Substitute(es, null, decrSubstMap);
- decrCallee.Add(exprTran.TrExpr(es));
- }
- return DecreasesCheck(decrToks, decrTypes, decrTypes, decrCallee, decrCaller, null, null, false, true);
- };
+ var ie = new IdentifierExpr(inFormal.tok, inFormal.Name);
+ ie.Var = inFormal; // resolve here
+ ie.Type = inFormal.Type; // resolve here
+ recursiveCallArgs.Add(ie);
+ }
+ }
+ var methodSel = new MemberSelectExpr(m.tok, recursiveCallReceiver, m.Name);
+ methodSel.Member = m; // resolve here
+ methodSel.TypeApplication = new List<Type>();
+ methodSel.TypeApplication.AddRange(recursiveCallReceiver.Type.TypeArgs);
+ m.TypeArgs.ForEach(tp => methodSel.TypeApplication.Add(new UserDefinedType(tp)));
+ methodSel.Type = new InferredTypeProxy(); // this is the last step in resolving 'methodSel'
+ var recursiveCall = new CallStmt(m.tok, m.tok, new List<Expression>(), methodSel, recursiveCallArgs);
+ recursiveCall.IsGhost = m.IsGhost; // resolve here
+
+ Expression parRange = new LiteralExpr(m.tok, true);
+ parRange.Type = Type.Bool; // resolve here
+ foreach (var pre in m.Req) {
+ if (!pre.IsFree) {
+ parRange = Expression.CreateAnd(parRange, Substitute(pre.E, null, substMap));
+ }
+ }
+ // construct an expression (generator) for: VF' << VF
+ ExpressionConverter decrCheck = delegate(Dictionary<IVariable, Expression> decrSubstMap, ExpressionTranslator exprTran) {
+ var decrToks = new List<IToken>();
+ var decrTypes = new List<Type>();
+ var decrCallee = new List<Expr>();
+ var decrCaller = new List<Expr>();
+ foreach (var ee in m.Decreases.Expressions) {
+ decrToks.Add(ee.tok);
+ decrTypes.Add(ee.Type.NormalizeExpand());
+ decrCaller.Add(exprTran.TrExpr(ee));
+ Expression es = Substitute(ee, null, substMap);
+ es = Substitute(es, null, decrSubstMap);
+ decrCallee.Add(exprTran.TrExpr(es));
+ }
+ return DecreasesCheck(decrToks, decrTypes, decrTypes, decrCallee, decrCaller, null, null, false, true);
+ };
#if VERIFY_CORRECTNESS_OF_TRANSLATION_FORALL_STATEMENT_RANGE
- var definedness = new Bpl.StmtListBuilder();
- var exporter = new Bpl.StmtListBuilder();
- TrForallStmtCall(m.tok, parBoundVars, parRange, decrCheck, recursiveCall, definedness, exporter, localVariables, etran);
- // All done, so put the two pieces together
- builder.Add(new Bpl.IfCmd(m.tok, null, definedness.Collect(m.tok), null, exporter.Collect(m.tok)));
+ var definedness = new Bpl.StmtListBuilder();
+ var exporter = new Bpl.StmtListBuilder();
+ TrForallStmtCall(m.tok, parBoundVars, parRange, decrCheck, null, recursiveCall, definedness, exporter, localVariables, etran);
+ // All done, so put the two pieces together
+ builder.Add(new Bpl.IfCmd(m.tok, null, definedness.Collect(m.tok), null, exporter.Collect(m.tok)));
#else
- TrForallStmtCall(m.tok, parBoundVars, parRange, decrCheck, recursiveCall, null, builder, localVariables, etran);
+ TrForallStmtCall(m.tok, parBoundVars, parRange, decrCheck, null, recursiveCall, null, builder, localVariables, etran);
#endif
- }
}
// translate the body of the method
Contract.Assert(m.Body != null); // follows from method precondition and the if guard
@@ -2861,8 +2911,7 @@ namespace Microsoft.Dafny {
} else {
// check well-formedness of the preconditions, and then assume each one of them
foreach (MaybeFreeExpression p in m.Req) {
- CheckWellformed(p.E, new WFOptions(), localVariables, builder, etran);
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);
}
// check well-formedness of the modifies clause
CheckFrameWellFormed(new WFOptions(), m.Mod.Expressions, localVariables, builder, etran);
@@ -2878,7 +2927,7 @@ namespace Microsoft.Dafny {
foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(m.tok, m.Mod.Expressions, m.IsGhost, etran.Old, etran, etran.Old))
{
if (tri.IsFree) {
- builder.Add(new Bpl.AssumeCmd(m.tok, tri.Expr));
+ builder.Add(TrAssumeCmd(m.tok, tri.Expr));
}
}
@@ -2900,8 +2949,7 @@ namespace Microsoft.Dafny {
// check wellformedness of postconditions
foreach (MaybeFreeExpression p in m.Ens) {
- CheckWellformed(p.E, new WFOptions(), localVariables, builder, etran);
- builder.Add(new Bpl.AssumeCmd(p.E.tok, etran.TrExpr(p.E)));
+ CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);
}
stmts = builder.Collect(m.tok);
@@ -2922,6 +2970,65 @@ namespace Microsoft.Dafny {
Reset();
}
+ void InitializeFuelConstant(IToken tok, Bpl.StmtListBuilder builder, ExpressionTranslator etran) {
+ if (this.functionFuel.Count > 0) {
+ builder.Add(new CommentCmd("initialize fuel constant"));
+ }
+ FuelContext fuelContext = this.fuelContext;
+ foreach (FuelConstant fuelConstant in this.functionFuel) {
+ Function f = fuelConstant.f;
+ Bpl.Expr baseFuel = fuelConstant.baseFuel;
+ Bpl.Expr startFuel = fuelConstant.startFuel;
+ Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;
+ // find out what the initial value should be
+ FuelSettingPair settings;
+ var found = fuelContext.TryGetValue(f, out settings);
+ if (!found) {
+ // If the context doesn't define fuel for this function, check for a fuel attribute (which supplies a default value if none is found)
+ settings = FuelSetting.FuelAttrib(f, out found);
+ }
+
+ Bpl.Expr layer = etran.layerInterCluster.LayerN(settings.low, baseFuel);
+ Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(settings.high, baseFuel);
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuel, layer)));
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuelAssert, layerAssert)));
+ }
+ }
+
+ bool DefineFuelConstant(IToken tok, Attributes attribs, Bpl.StmtListBuilder builder, ExpressionTranslator etran) {
+ bool defineFuel = false;
+ builder.Add(new CommentCmd("Assume Fuel Constant"));
+ FuelContext fuelContext = new FuelContext();
+ FuelSetting.FindFuelAttributes(attribs, fuelContext);
+ foreach (KeyValuePair<Function, FuelSettingPair> fuel in fuelContext) {
+ Function f = fuel.Key;
+ FuelSettingPair settings = fuel.Value;
+ FuelConstant fuelConstant = this.functionFuel.Find(x => x.f == f);
+ if (fuelConstant != null) {
+ Bpl.Expr startFuel = fuelConstant.startFuel;
+ Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;
+ Bpl.Expr moreFuel_expr = fuelConstant.MoreFuel(sink, predef, f.IdGenerator);
+ Bpl.Expr layer = etran.layerInterCluster.LayerN(settings.low, moreFuel_expr);
+ Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(settings.high, moreFuel_expr);
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuel, layer)));
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuelAssert, layerAssert)));
+ defineFuel = true;
+ }
+ }
+ return defineFuel;
+ }
+
+ internal static AssumeCmd optimizeExpr(bool minimize, Expression expr, IToken tok, ExpressionTranslator etran)
+ {
+ Contract.Requires(expr != null);
+ Contract.Requires(expr.Type.IsIntegerType || expr.Type.IsRealType);
+ Contract.Requires(tok != null && etran != null);
+
+ var assumeCmd = new AssumeCmd(tok, Expr.True);
+ assumeCmd.Attributes = new QKeyValue(expr.tok, (minimize ? "minimize" : "maximize"), new List<object> { etran.TrExpr(expr) }, null);
+ return assumeCmd;
+ }
+
private void AddFunctionOverrideCheckImpl(Function f)
{
Contract.Requires(f != null);
@@ -2968,7 +3075,7 @@ namespace Microsoft.Dafny {
{
var functionHeight = currentModule.CallGraph.GetSCCRepresentativeId(f);
var splits = new List<SplitExprInfo>();
- bool splitHappened/*we actually don't care*/ = TrSplitExpr(p, splits, true, functionHeight,false, etran);
+ bool splitHappened/*we actually don't care*/ = TrSplitExpr(p, splits, true, functionHeight, true, false, etran);
foreach (var s in splits)
{
if (s.IsChecked && !RefinementToken.IsInherited(s.E.tok, currentModule))
@@ -3004,7 +3111,7 @@ namespace Microsoft.Dafny {
AddFunctionOverrideReqsChk(f, builder, etran, substMap);
//adding assert R <= Rank’;
- AddFunctionOverrideTerminationChk(f, builder, etran, substMap);
+ AddOverrideTerminationChk(f, f.OverriddenFunction, builder, etran, substMap);
//adding assert W <= Frame’
AddFunctionOverrideSubsetChk(f, builder, etran, localVariables, substMap);
@@ -3069,7 +3176,7 @@ namespace Microsoft.Dafny {
//generating class post-conditions
foreach (var en in f.Ens)
{
- builder.Add(new Bpl.AssumeCmd(f.tok, etran.TrExpr(en)));
+ builder.Add(TrAssumeCmd(f.tok, etran.TrExpr(en)));
}
//generating assume J.F(ins) == C.F(ins)
@@ -3077,13 +3184,13 @@ namespace Microsoft.Dafny {
Bpl.FunctionCall funcIdT = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.OverriddenFunction.tok, f.OverriddenFunction.FullSanitizedName, TrType(f.OverriddenFunction.ResultType)));
List<Bpl.Expr> argsC = new List<Bpl.Expr>();
List<Bpl.Expr> argsT = new List<Bpl.Expr>();
- if (f.IsRecursive)
+ if (f.IsFuelAware())
{
- argsC.Add(etran.LayerN(1));
+ argsC.Add(etran.layerInterCluster.GetFunctionFuel(f));
}
- if (f.OverriddenFunction.IsRecursive)
+ if (f.OverriddenFunction.IsFuelAware())
{
- argsT.Add(etran.LayerN(1));
+ argsT.Add(etran.layerInterCluster.GetFunctionFuel(f));
}
argsC.Add(etran.HeapExpr);
argsT.Add(etran.HeapExpr);
@@ -3094,7 +3201,7 @@ namespace Microsoft.Dafny {
}
Bpl.Expr funcExpC = new Bpl.NAryExpr(f.tok, funcIdC, argsC);
Bpl.Expr funcExpT = new Bpl.NAryExpr(f.OverriddenFunction.tok, funcIdT, argsT);
- builder.Add(new Bpl.AssumeCmd(f.tok, Bpl.Expr.Eq(funcExpC, funcExpT)));
+ builder.Add(TrAssumeCmd(f.tok, Bpl.Expr.Eq(funcExpC, funcExpT)));
//generating trait post-conditions with class variables
foreach (var en in f.OverriddenFunction.Ens)
@@ -3104,7 +3211,7 @@ namespace Microsoft.Dafny {
var reqSplitedE = TrSplitExpr(postcond, etran,false, out splitHappened);
foreach (var s in reqSplitedE)
{
- var assert = new Bpl.AssertCmd(f.tok, s.E);
+ var assert = TrAssertCmd(f.tok, s.E);
assert.ErrorData = "Error: the function must provide an equal or more detailed postcondition than in its parent trait";
builder.Add(assert);
}
@@ -3120,7 +3227,7 @@ namespace Microsoft.Dafny {
{
if (tri.IsFree)
{
- builder.Add(new Bpl.AssumeCmd(f.tok, tri.Expr));
+ builder.Add(TrAssumeCmd(f.tok, tri.Expr));
}
}
}
@@ -3167,42 +3274,13 @@ namespace Microsoft.Dafny {
builder.Add(Assert(tok, q, "expression may read an object not in the parent trait context's reads clause", kv));
}
- private void AddFunctionOverrideTerminationChk(Function f, StmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap)
- {
- var decrToks = new List<IToken>();
- var decrTypes1 = new List<Type>();
- var decrTypes2 = new List<Type>();
- var decrClass = new List<Expr>();
- var decrTrait = new List<Expr>();
- if (f.Decreases != null)
- {
- foreach (var decC in f.Decreases.Expressions)
- {
- decrToks.Add(decC.tok);
- decrTypes1.Add(decC.Type);
- decrClass.Add(etran.TrExpr(decC));
- }
- }
- if (f.OverriddenFunction.Decreases != null)
- {
- foreach (var decT in f.OverriddenFunction.Decreases.Expressions)
- {
- var decCNew = Substitute(decT, null, substMap);
- decrTypes2.Add(decCNew.Type);
- decrTrait.Add(etran.TrExpr(decCNew));
- }
- }
- var decrChk = DecreasesCheck(decrToks, decrTypes1, decrTypes2, decrClass, decrTrait, null, null, true, false);
- builder.Add(new Bpl.AssertCmd(f.tok, decrChk));
- }
-
private void AddFunctionOverrideReqsChk(Function f, StmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap)
{
//generating trait pre-conditions with class variables
foreach (var req in f.OverriddenFunction.Req)
{
Expression precond = Substitute(req, null, substMap);
- builder.Add(new Bpl.AssumeCmd(f.tok, etran.TrExpr(precond)));
+ builder.Add(TrAssumeCmd(f.tok, etran.TrExpr(precond)));
}
//generating class pre-conditions
foreach (var req in f.Req)
@@ -3211,7 +3289,7 @@ namespace Microsoft.Dafny {
var reqSplitedE = TrSplitExpr(req, etran,false, out splitHappened);
foreach (var s in reqSplitedE)
{
- var assert = new Bpl.AssertCmd(f.tok, s.E);
+ var assert = TrAssertCmd(f.tok, s.E);
assert.ErrorData = "Error: the function must provide an equal or more permissive precondition than in its parent trait";
builder.Add(assert);
}
@@ -3263,7 +3341,7 @@ namespace Microsoft.Dafny {
AddMethodOverrideReqsChk(m, builder, etran, substMap);
//adding assert R <= Rank’;
- AddMethodOverrideTerminationChk(m, builder, etran, substMap);
+ AddOverrideTerminationChk(m, m.OverriddenMethod, builder, etran, substMap);
//adding assert W <= Frame’
AddMethodOverrideSubsetChk(m, builder, etran, localVariables, substMap);
@@ -3301,7 +3379,7 @@ namespace Microsoft.Dafny {
{
if (tri.IsFree)
{
- builder.Add(new Bpl.AssumeCmd(m.tok, tri.Expr));
+ builder.Add(TrAssumeCmd(m.tok, tri.Expr));
}
}
}
@@ -3311,7 +3389,7 @@ namespace Microsoft.Dafny {
//generating class post-conditions
foreach (var en in m.Ens)
{
- builder.Add(new Bpl.AssumeCmd(m.tok, etran.TrExpr(en.E)));
+ builder.Add(TrAssumeCmd(m.tok, etran.TrExpr(en.E)));
}
//generating trait post-conditions with class variables
foreach (var en in m.OverriddenMethod.Ens)
@@ -3321,7 +3399,7 @@ namespace Microsoft.Dafny {
var reqSplitedE = TrSplitExpr(postcond, etran,false, out splitHappened);
foreach (var s in reqSplitedE)
{
- var assert = new Bpl.AssertCmd(m.tok, s.E);
+ var assert = TrAssertCmd(m.tok, s.E);
assert.ErrorData = "Error: the method must provide an equal or more detailed postcondition than in its parent trait";
builder.Add(assert);
}
@@ -3334,7 +3412,7 @@ namespace Microsoft.Dafny {
foreach (var req in m.OverriddenMethod.Req)
{
Expression precond = Substitute(req.E, null, substMap);
- builder.Add(new Bpl.AssumeCmd(m.tok, etran.TrExpr(precond)));
+ builder.Add(TrAssumeCmd(m.tok, etran.TrExpr(precond)));
}
//generating class pre-conditions
foreach (var req in m.Req)
@@ -3343,21 +3421,22 @@ namespace Microsoft.Dafny {
var reqSplitedE = TrSplitExpr(req.E, etran,false, out splitHappened);
foreach (var s in reqSplitedE)
{
- var assert = new Bpl.AssertCmd(m.tok, s.E);
+ var assert = TrAssertCmd(m.tok, s.E);
assert.ErrorData = "Error: the method must provide an equal or more permissive precondition than in its parent trait";
builder.Add(assert);
}
}
}
- private void AddMethodOverrideTerminationChk(Method m, Bpl.StmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap) {
- Contract.Requires(m != null);
+ private void AddOverrideTerminationChk(ICallable original, ICallable overryd, Bpl.StmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap) {
+ Contract.Requires(original != null);
+ Contract.Requires(overryd != null);
Contract.Requires(builder != null);
Contract.Requires(etran != null);
Contract.Requires(substMap != null);
// Note, it is as if the trait's method is calling the class's method.
- var contextDecreases = m.OverriddenMethod.Decreases.Expressions;
- var calleeDecreases = m.Decreases.Expressions;
+ var contextDecreases = overryd.Decreases.Expressions;
+ var calleeDecreases = original.Decreases.Expressions;
// We want to check: calleeDecreases <= contextDecreases (note, we can allow equality, since there is a bounded, namely 1, number of dynamic dispatches)
if (Contract.Exists(contextDecreases, e => e is WildcardExpr)) {
// no check needed
@@ -3378,7 +3457,7 @@ namespace Microsoft.Dafny {
N = i;
break;
}
- toks.Add(new NestedToken(m.tok, e1.tok));
+ toks.Add(new NestedToken(original.Tok, e1.tok));
types0.Add(e0.Type.NormalizeExpand());
types1.Add(e1.Type.NormalizeExpand());
callee.Add(etran.TrExpr(e0));
@@ -3411,7 +3490,7 @@ namespace Microsoft.Dafny {
// as "false".
bool allowNoChange = N == decrCountT && decrCountT <= decrCountC;
var decrChk = DecreasesCheck(toks, types0, types1, callee, caller, null, null, allowNoChange, false);
- builder.Add(Assert(m.tok, decrChk, "method's decreases clause must be below or equal to that in the trait"));
+ builder.Add(Assert(original.Tok, decrChk, string.Format("{0}'s decreases clause must be below or equal to that in the trait", original.WhatKind)));
}
private void AddMethodOverrideSubsetChk(Method m, Bpl.StmtListBuilder builder, ExpressionTranslator etran, List<Variable> localVariables, Dictionary<IVariable, Expression> substMap)
@@ -3515,10 +3594,13 @@ namespace Microsoft.Dafny {
private void InsertChecksum(Function f, Bpl.Declaration decl, bool specificationOnly = false)
{
+ Contract.Requires(f != null);
+ Contract.Requires(decl != null);
byte[] data;
using (var writer = new System.IO.StringWriter())
{
var printer = new Printer(writer);
+ writer.Write(f.IsGhost ? "function" : "function method");
printer.PrintAttributes(f.Attributes);
printer.PrintFormals(f.Formals);
writer.Write(": ");
@@ -3539,6 +3621,8 @@ namespace Microsoft.Dafny {
private void InsertChecksum(Bpl.Declaration decl, byte[] data)
{
+ Contract.Requires(decl != null);
+ Contract.Requires(data != null);
var md5 = System.Security.Cryptography.MD5.Create();
var hashedData = md5.ComputeHash(data);
var checksum = BitConverter.ToString(hashedData);
@@ -3615,9 +3699,9 @@ namespace Microsoft.Dafny {
Contract.Requires(tok != null);
Contract.Ensures(Contract.Result<Bpl.Cmd>() != null);
var col = tok.col + (isEndToken ? tok.val.Length : 0);
- string description = string.Format("{0}({1},{2}){3}{4}", tok.filename, tok.line, col, additionalInfo == null ? "" : ": ", additionalInfo ?? "");
+ string description = ErrorReporter.ErrorToString_Internal(additionalInfo == null ? "" : ": ", tok.filename, tok.line, col, additionalInfo ?? "");
QKeyValue kv = new QKeyValue(tok, "captureState", new List<object>() { description }, null);
- return new Bpl.AssumeCmd(tok, Bpl.Expr.True, kv);
+ return TrAssumeCmd(tok, Bpl.Expr.True, kv);
}
Bpl.Cmd CaptureState(Statement stmt) {
Contract.Requires(stmt != null);
@@ -3696,9 +3780,9 @@ namespace Microsoft.Dafny {
/// <summary>
/// Generates:
/// axiom (forall s, h0: HeapType, h1: HeapType, formals... ::
- /// { HeapSucc(h0,h1), F(s,h1,formals) }
+ /// { IsHeapAnchor(h0), HeapSucc(h0,h1), F(s,h1,formals) }
/// heaps are well-formed and formals are allocated AND
- /// HeapSucc(h0,h1)
+ /// IsHeapAnchor(h0) AND HeapSucc(h0,h1)
/// AND
/// (forall(alpha) o: ref, f: Field alpha ::
/// o != null AND h0[o,alloc] AND h1[o,alloc] AND
@@ -3730,7 +3814,7 @@ namespace Microsoft.Dafny {
var typeParams = TrTypeParamDecls(f.TypeArgs);
{
var formals = new List<Variable>();
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType), true));
}
if (!f.IsStatic) {
@@ -3754,7 +3838,7 @@ namespace Microsoft.Dafny {
List<Bpl.Expr> argsF = new List<Bpl.Expr>();
List<Bpl.Expr> argsFFrame = new List<Bpl.Expr>();
List<Bpl.Expr> argsCanCall = new List<Bpl.Expr>();
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
var sV = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType));
var s = new Bpl.IdentifierExpr(f.tok, sV);
bvars.Add(sV);
@@ -3817,7 +3901,8 @@ namespace Microsoft.Dafny {
Bpl.Expr oNotNullAlloced = Bpl.Expr.And(oNotNull, Bpl.Expr.And(etran0.IsAlloced(f.tok, o), etran1.IsAlloced(f.tok, o)));
Bpl.Expr unchanged = Bpl.Expr.Eq(ReadHeap(f.tok, h0, o, field), ReadHeap(f.tok, h1, o, field));
- Bpl.Expr heapSucc = FunctionCall(f.tok, BuiltinFunction.HeapSucc, null, h0, h1);
+ Bpl.Expr h0IsHeapAnchor = FunctionCall(h0.tok, BuiltinFunction.IsHeapAnchor, null, h0);
+ Bpl.Expr heapSucc = HeapSucc(h0, h1);
Bpl.Expr r0 = InRWClause(f.tok, o, field, f.Reads, etran0, null, null);
Bpl.Expr q0 = new Bpl.ForallExpr(f.tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fieldVar },
Bpl.Expr.Imp(Bpl.Expr.And(oNotNullAlloced, r0), unchanged));
@@ -3828,7 +3913,7 @@ namespace Microsoft.Dafny {
var f1args = new List<Bpl.Expr>(tyexprs);
var f0argsCanCall = new List<Bpl.Expr>(tyexprs);
var f1argsCanCall = new List<Bpl.Expr>(tyexprs);
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
Bpl.Expr s; var sV = BplBoundVar("$ly", predef.LayerType, out s);
bvars.Add(sV);
f0args.Add(s); f1args.Add(s); // but don't add to f0argsCanCall or f1argsCanCall
@@ -3877,11 +3962,11 @@ namespace Microsoft.Dafny {
var F0 = new Bpl.NAryExpr(f.tok, fn, f0args);
var F1 = new Bpl.NAryExpr(f.tok, fn, f1args);
var eq = Bpl.Expr.Eq(F0, F1);
- var tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { heapSucc, F1 });
+ var tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { h0IsHeapAnchor, heapSucc, F1 });
var typeParams = TrTypeParamDecls(f.TypeArgs);
var ax = new Bpl.ForallExpr(f.tok, typeParams, bvars, null, tr,
- Bpl.Expr.Imp(Bpl.Expr.And(wellFormed, heapSucc),
+ Bpl.Expr.Imp(Bpl.Expr.And(wellFormed, Bpl.Expr.And(h0IsHeapAnchor, heapSucc)),
Bpl.Expr.Imp(q0, eq)));
sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, ax, comment));
#endif
@@ -3949,7 +4034,8 @@ namespace Microsoft.Dafny {
Bpl.Expr iBounds = InSeqRange(tok, i, etran.TrExpr(e), true, null, false);
Bpl.Expr XsubI = FunctionCall(tok, BuiltinFunction.SeqIndex, predef.BoxType, etran.TrExpr(e), i);
// TODO: the equality in the next line should be changed to one that understands extensionality
- disjunct = new Bpl.ExistsExpr(tok, new List<Variable> { iVar }, Bpl.Expr.And(iBounds, Bpl.Expr.Eq(XsubI, boxO)));
+ //TRIG (exists $i: int :: 0 <= $i && $i < Seq#Length(read($h0, this, _module.DoublyLinkedList.Nodes)) && Seq#Index(read($h0, this, _module.DoublyLinkedList.Nodes), $i) == $Box($o))
+ disjunct = new Bpl.ExistsExpr(tok, new List<Variable> { iVar }, Bpl.Expr.And(iBounds, Bpl.Expr.Eq(XsubI, boxO))); // LL_TRIGGER
} else {
// o == e
disjunct = Bpl.Expr.Eq(o, etran.TrExpr(e));
@@ -4003,7 +4089,7 @@ namespace Microsoft.Dafny {
foreach (Expression p in f.Ens) {
var functionHeight = currentModule.CallGraph.GetSCCRepresentativeId(f);
var splits = new List<SplitExprInfo>();
- bool splitHappened /*we actually don't care*/ = TrSplitExpr(p, splits, true, functionHeight, true, etran);
+ bool splitHappened /*we actually don't care*/ = TrSplitExpr(p, splits, true, functionHeight, true, true, etran);
foreach (var s in splits) {
if (s.IsChecked && !RefinementToken.IsInherited(s.E.tok, currentModule)) {
ens.Add(Ensures(s.E.tok, false, s.E, null, null));
@@ -4025,27 +4111,28 @@ namespace Microsoft.Dafny {
var implInParams = Bpl.Formal.StripWhereClauses(inParams);
var locals = new List<Variable>();
var builder = new Bpl.StmtListBuilder();
+ var builderInitializationArea = new Bpl.StmtListBuilder();
builder.Add(new CommentCmd("AddWellformednessCheck for function " + f));
builder.Add(CaptureState(f.tok, false, "initial state"));
DefineFrame(f.tok, f.Reads, builder, locals, null);
-
- // check well-formedness of the preconditions (including termination, and reads checks), and then
- // assume each one of them
- var wfo = new WFOptions(null, true, true /* do delayed reads checks over requires */);
-
- // check well-formedness of the reads clause
- CheckFrameWellFormed(wfo, f.Reads, locals, builder, etran);
-
- // check the reads of the preconditions now
- foreach (var a in wfo.Asserts) {
- builder.Add(a);
- }
-
+ InitializeFuelConstant(f.tok, builder, etran);
+ // Check well-formedness of the preconditions (including termination), and then
+ // assume each one of them. After all that (in particular, after assuming all
+ // of them), do the postponed reads checks.
+ var wfo = new WFOptions(null, true, true /* do delayed reads checks */);
foreach (Expression p in f.Req) {
- CheckWellformed(p, new WFOptions(null, true /* do reads checks */), locals, builder, etran);
- builder.Add(new Bpl.AssumeCmd(p.tok, etran.TrExpr(p)));
+ CheckWellformedAndAssume(p, wfo, locals, builder, etran);
}
+ wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, builder);
+
+ // Check well-formedness of the reads clause. Note that this is done after assuming
+ // the preconditions. In other words, the well-formedness of the reads clause is
+ // allowed to assume the precondition (yet, the requires clause is checked to
+ // read only those things indicated in the reads clause).
+ wfo = new WFOptions(null, true, true /* do delayed reads checks */);
+ CheckFrameWellFormed(wfo, f.Reads, locals, builder, etran);
+ wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, builder);
// check well-formedness of the decreases clauses (including termination, but no reads checks)
foreach (Expression p in f.Decreases.Expressions)
@@ -4068,8 +4155,8 @@ namespace Microsoft.Dafny {
foreach (var p in GetTypeParams(f)) {
args.Add(trTypeParam(p, null));
}
- if (f.IsRecursive) {
- args.Add(etran.LayerN(1));
+ if (f.IsFuelAware()) {
+ args.Add(etran.layerInterCluster.GetFunctionFuel(f));
}
args.Add(etran.HeapExpr);
if (!f.IsStatic) {
@@ -4083,28 +4170,27 @@ namespace Microsoft.Dafny {
var wh = GetWhereClause(f.tok, funcAppl, f.ResultType, etran);
if (wh != null) {
- postCheckBuilder.Add(new Bpl.AssumeCmd(f.tok, wh));
+ postCheckBuilder.Add(TrAssumeCmd(f.tok, wh));
}
}
// Now for the ensures clauses
foreach (Expression p in f.Ens) {
- CheckWellformed(p, new WFOptions(f, false), locals, postCheckBuilder, etran);
// assume the postcondition for the benefit of checking the remaining postconditions
- postCheckBuilder.Add(new Bpl.AssumeCmd(p.tok, etran.TrExpr(p)));
+ CheckWellformedAndAssume(p, new WFOptions(f, false), locals, postCheckBuilder, etran);
}
// Here goes the body (and include both termination checks and reads checks)
StmtListBuilder bodyCheckBuilder = new StmtListBuilder();
if (f.Body == null) {
// don't fall through to postcondition checks
- bodyCheckBuilder.Add(new Bpl.AssumeCmd(f.tok, Bpl.Expr.False));
+ bodyCheckBuilder.Add(TrAssumeCmd(f.tok, Bpl.Expr.False));
} else {
Bpl.FunctionCall funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));
List<Bpl.Expr> args = new List<Bpl.Expr>();
foreach (var p in GetTypeParams(f)) {
args.Add(trTypeParam(p, null));
}
- if (f.IsRecursive) {
- args.Add(etran.LayerN(1));
+ if (f.IsFuelAware()) {
+ args.Add(etran.layerInterCluster.GetFunctionFuel(f));
}
args.Add(etran.HeapExpr);
foreach (Variable p in implInParams) {
@@ -4119,22 +4205,20 @@ namespace Microsoft.Dafny {
* makes reads clauses also guard the requires */
, null);
- CheckWellformedWithResult(f.Body, new WFOptions(null, true), funcAppl, f.ResultType, locals, bodyCheckBuilder, etran);
+ wfo = new WFOptions(null, true, true /* do delayed reads checks */);
+ CheckWellformedWithResult(f.Body, wfo, funcAppl, f.ResultType, locals, bodyCheckBuilder, etran);
+ wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, bodyCheckBuilder);
}
// Combine the two, letting the postcondition be checked on after the "bodyCheckBuilder" branch
- postCheckBuilder.Add(new Bpl.AssumeCmd(f.tok, Bpl.Expr.False));
+ postCheckBuilder.Add(TrAssumeCmd(f.tok, Bpl.Expr.False));
builder.Add(new Bpl.IfCmd(f.tok, null, postCheckBuilder.Collect(f.tok), null, bodyCheckBuilder.Collect(f.tok)));
- // var b$reads_guards_requires#0 : bool
- locals.AddRange(wfo.Locals);
- // This ugly way seems to be the way to add things at the start of a builder:
- StmtList sl = builder.Collect(f.tok);
- // b$reads_guards_requires#0 := true ...
- sl.BigBlocks[0].simpleCmds.InsertRange(0, wfo.AssignLocals);
-
+ var s0 = builderInitializationArea.Collect(f.tok);
+ var s1 = builder.Collect(f.tok);
+ var implBody = new StmtList(new List<BigBlock>(s0.BigBlocks.Concat(s1.BigBlocks)), f.tok);
Bpl.Implementation impl = new Bpl.Implementation(f.tok, proc.Name,
typeParams, Concat(typeInParams, implInParams), new List<Variable>(),
- locals, sl, etran.TrAttributes(f.Attributes, null));
+ locals, implBody, etran.TrAttributes(f.Attributes, null));
sink.AddTopLevelDeclaration(impl);
if (InsertChecksums)
@@ -4241,7 +4325,7 @@ namespace Microsoft.Dafny {
Type t = mc.Ctor.Formals[i].Type;
Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, local), p.Type, etran);
if (wh != null) {
- localTypeAssumptions.Add(new Bpl.AssumeCmd(p.tok, wh));
+ localTypeAssumptions.Add(TrAssumeCmd(p.tok, wh));
}
args.Add(CondApplyBox(mc.tok, new Bpl.IdentifierExpr(p.tok, local), cce.NonNull(p.Type), t));
}
@@ -4293,12 +4377,7 @@ namespace Microsoft.Dafny {
return CanCallAssumption(l, etran);
} else if (expr is MemberSelectExpr) {
MemberSelectExpr e = (MemberSelectExpr)expr;
- Bpl.Expr r;
- if (e.Obj is ThisExpr) {
- r = Bpl.Expr.True;
- } else {
- r = CanCallAssumption(e.Obj, etran);
- }
+ var r = CanCallAssumption(e.Obj, etran);
if (e.Member is DatatypeDestructor) {
var dtor = (DatatypeDestructor)e.Member;
if (dtor.EnclosingCtor.EnclosingDatatype.Ctors.Count == 1) {
@@ -4311,10 +4390,7 @@ namespace Microsoft.Dafny {
} else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
Bpl.Expr total = CanCallAssumption(e.Seq, etran);
- Bpl.Expr seq = etran.TrExpr(e.Seq);
- Bpl.Expr e0 = null;
if (e.E0 != null) {
- e0 = etran.TrExpr(e.E0);
total = BplAnd(total, CanCallAssumption(e.E0, etran));
}
if (e.E1 != null) {
@@ -4335,8 +4411,6 @@ namespace Microsoft.Dafny {
return CanCallAssumption(e.ResolvedUpdateExpr, etran);
}
Bpl.Expr total = CanCallAssumption(e.Seq, etran);
- Bpl.Expr seq = etran.TrExpr(e.Seq);
- Bpl.Expr index = etran.TrExpr(e.Index);
total = BplAnd(total, CanCallAssumption(e.Index, etran));
total = BplAnd(total, CanCallAssumption(e.Value, etran));
return total;
@@ -4347,18 +4421,13 @@ namespace Microsoft.Dafny {
e.Args.ConvertAll(ee => CanCallAssumption(ee, etran))));
} else if (expr is FunctionCallExpr) {
FunctionCallExpr e = (FunctionCallExpr)expr;
- // check well-formedness of receiver
Bpl.Expr r = CanCallAssumption(e.Receiver, etran);
- // check well-formedness of the other parameters
r = BplAnd(r, CanCallAssumption(e.Args, etran));
- // if (e.Name != "requires" && e.Name != "reads") {
- Contract.Assert(e.Function != null); // follows from the fact that expr has been successfully resolved
- // get to assume canCall
- Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, e.Function.FullSanitizedName + "#canCall", Bpl.Type.Bool);
- List<Bpl.Expr> args = etran.FunctionInvocationArguments(e, null);
- Bpl.Expr canCallFuncAppl = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);
- r = BplAnd(r, canCallFuncAppl);
- // }
+ // get to assume canCall
+ Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, e.Function.FullSanitizedName + "#canCall", Bpl.Type.Bool);
+ List<Bpl.Expr> args = etran.FunctionInvocationArguments(e, null);
+ Bpl.Expr canCallFuncAppl = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);
+ r = BplAnd(r, canCallFuncAppl);
return r;
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
@@ -4379,10 +4448,10 @@ namespace Microsoft.Dafny {
switch (e.ResolvedOp) {
case BinaryExpr.ResolvedOpcode.And:
case BinaryExpr.ResolvedOpcode.Imp:
- t1 = Bpl.Expr.Imp(etran.TrExpr(e.E0), t1);
+ t1 = BplImp(etran.TrExpr(e.E0), t1);
break;
case BinaryExpr.ResolvedOpcode.Or:
- t1 = Bpl.Expr.Imp(Bpl.Expr.Not(etran.TrExpr(e.E0)), t1);
+ t1 = BplImp(Bpl.Expr.Not(etran.TrExpr(e.E0)), t1);
break;
default:
break;
@@ -4413,20 +4482,23 @@ namespace Microsoft.Dafny {
var canCallBody = CanCallAssumption(Substitute(e.Body, null, substMap), etran);
return BplAnd(canCallRHS, canCallBody);
} else {
- // CanCall[[ var b :| RHS(b,g); Body(b,g,h) ]] =
- // (forall b :: typeAntecedent ==>
- // CanCall[[ RHS(b,g) ]] &&
- // (RHS(b,g) ==> CanCall[[ Body(b,g,h) ]]) &&
- // $let$canCall(b,g))
- var bvars = new List<Variable>();
- Bpl.Expr typeAntecedent = etran.TrBoundVariables(e.BoundVars.ToList<BoundVar>(), bvars);
- Contract.Assert(e.RHSs.Count == 1); // this is true of all successfully resolved let-such-that expressions
- var canCallRHS = CanCallAssumption(e.RHSs[0], etran);
- var canCallBody = Bpl.Expr.Imp(etran.TrExpr(e.RHSs[0]), CanCallAssumption(e.Body, etran));
- var d = LetDesugaring(e); // call LetDesugaring to prepare the desugaring and populate letSuchThatExprInfo with something for e
+ // CanCall[[ var b0,b1 :| RHS(b0,b1,g); Body(b0,b1,g,h) ]] =
+ // $let$canCall(g) &&
+ // CanCall[[ Body($let$b0(g), $let$b1(g), h) ]]
+ LetDesugaring(e); // call LetDesugaring to prepare the desugaring and populate letSuchThatExprInfo with something for e
var info = letSuchThatExprInfo[e];
- var canCallFunction = info.CanCallFunctionCall(this, etran);
- var cc = new Bpl.ForallExpr(e.tok, bvars, Bpl.Expr.Imp(typeAntecedent, BplAnd(BplAnd(canCallRHS, canCallBody), canCallFunction)));
+ // $let$canCall(g)
+ var canCall = info.CanCallFunctionCall(this, etran);
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ foreach (var bv in e.BoundVars) {
+ // create a call to $let$x(g)
+ var args = info.SkolemFunctionArgs(bv, this, etran);
+ var call = new BoogieFunctionCall(bv.tok, info.SkolemFunctionName(bv), info.UsesHeap, info.UsesOldHeap, args.Item1, args.Item2);
+ call.Type = bv.Type;
+ substMap.Add(bv, call);
+ }
+ var p = Substitute(e.Body, null, substMap);
+ var cc = BplAnd(canCall, CanCallAssumption(p, etran));
return cc;
}
@@ -4436,45 +4508,64 @@ namespace Microsoft.Dafny {
if (e.Contract != null)
return BplAnd(canCall, CanCallAssumption(e.Contract, etran));
else return canCall;
+
} else if (expr is LambdaExpr) {
var e = (LambdaExpr)expr;
- List<Bpl.Variable> bvars = new List<Bpl.Variable>();
-
+ var bvarsAndAntecedents = new List<Tuple<Bpl.Variable, Bpl.Expr>>();
var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator("$l#");
Bpl.Expr heap; var hVar = BplBoundVar(varNameGen.FreshId("#heap#"), predef.HeapType, out heap);
- bvars.Add(hVar);
+ var et = new ExpressionTranslator(etran, heap);
Dictionary<IVariable, Expression> subst = new Dictionary<IVariable,Expression>();
foreach (var bv in e.BoundVars) {
Bpl.Expr ve; var yVar = BplBoundVar(varNameGen.FreshId(string.Format("#{0}#", bv.Name)), TrType(bv.Type), out ve);
- bvars.Add(yVar);
+ var wh = GetWhereClause(bv.tok, new Bpl.IdentifierExpr(bv.tok, yVar), bv.Type, et);
+ bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(yVar, wh));
subst[bv] = new BoogieWrapper(ve, bv.Type);
}
- ExpressionTranslator et = new ExpressionTranslator(etran, heap);
- var ebody = CanCallAssumption(Substitute(e.Body, null, subst), et);
- return BplForall(bvars, ebody);
+ var canCall = CanCallAssumption(Substitute(e.Body, null, subst), et);
+ if (e.Range != null) {
+ var range = Substitute(e.Range, null, subst);
+ canCall = BplAnd(CanCallAssumption(range, etran), BplImp(etran.TrExpr(range), canCall));
+ }
+
+ // It's important to add the heap last to "bvarsAndAntecedents", because the heap may occur in the antecedents of
+ // the other variables and BplForallTrim processes the given tuples in order.
+ var goodHeap = FunctionCall(e.tok, BuiltinFunction.IsGoodHeap, null, heap);
+ bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(hVar, goodHeap));
+
+ //TRIG (forall $l#0#heap#0: Heap, $l#0#x#0: int :: true)
+ //TRIG (forall $l#0#heap#0: Heap, $l#0#t#0: DatatypeType :: _module.__default.TMap#canCall(_module._default.TMap$A, _module._default.TMap$B, $l#0#heap#0, $l#0#t#0, f#0))
+ //TRIG (forall $l#4#heap#0: Heap, $l#4#x#0: Box :: _0_Monad.__default.Bind#canCall(Monad._default.Associativity$B, Monad._default.Associativity$C, $l#4#heap#0, Apply1(Monad._default.Associativity$A, #$M$B, f#0, $l#4#heap#0, $l#4#x#0), g#0))
+ return BplForallTrim(bvarsAndAntecedents, null, canCall); // L_TRIGGER
+
} else if (expr is ComprehensionExpr) {
var e = (ComprehensionExpr)expr;
- var canCall = CanCallAssumption(e.Term, etran);
var q = e as QuantifierExpr;
- var tyvars = MkTyParamBinders(q != null ? q.TypeArgs : new List<TypeParameter>());
+ if (q != null && q.SplitQuantifier != null) {
+ return CanCallAssumption(q.SplitQuantifierExpression, etran);
+ }
+
+ // Determine the CanCall's for the range and term
+ var canCall = CanCallAssumption(e.Term, etran);
if (e.Range != null) {
canCall = BplAnd(CanCallAssumption(e.Range, etran), BplImp(etran.TrExpr(e.Range), canCall));
}
- if (canCall != Bpl.Expr.True) {
- List<Variable> bvars = new List<Variable>();
- Bpl.Expr typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars);
- if (Attributes.Contains(e.Attributes, "trigger")) {
- Bpl.Trigger tr = TrTrigger(etran, e.Attributes, expr.tok);
- canCall = new Bpl.ForallExpr(expr.tok, Concat(tyvars, bvars), tr, Bpl.Expr.Imp(typeAntecedent, canCall));
- } else {
- canCall = new Bpl.ForallExpr(expr.tok, Concat(tyvars, bvars), Bpl.Expr.Imp(typeAntecedent, canCall));
+ // Create a list of all possible bound variables
+ var bvarsAndAntecedents = etran.TrBoundVariables_SeparateWhereClauses(e.BoundVars);
+ if (q != null) {
+ var tyvars = MkTyParamBinders(q.TypeArgs);
+ foreach (var tv in tyvars) {
+ bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(tv, null));
}
}
- return canCall;
+ // Produce the quantified CanCall expression, with a suitably reduced set of bound variables
+ var tr = TrTrigger(etran, e.Attributes, expr.tok);
+ return BplForallTrim(bvarsAndAntecedents, tr, canCall);
+
} else if (expr is StmtExpr) {
var e = (StmtExpr)expr;
return CanCallAssumption(e.E, etran);
@@ -4482,8 +4573,8 @@ namespace Microsoft.Dafny {
ITEExpr e = (ITEExpr)expr;
Bpl.Expr total = CanCallAssumption(e.Test, etran);
Bpl.Expr test = etran.TrExpr(e.Test);
- total = BplAnd(total, Bpl.Expr.Imp(test, CanCallAssumption(e.Thn, etran)));
- total = BplAnd(total, Bpl.Expr.Imp(Bpl.Expr.Not(test), CanCallAssumption(e.Els, etran)));
+ total = BplAnd(total, BplImp(test, CanCallAssumption(e.Thn, etran)));
+ total = BplAnd(total, BplImp(Bpl.Expr.Not(test), CanCallAssumption(e.Els, etran)));
return total;
} else if (expr is ConcreteSyntaxExpression) {
var e = (ConcreteSyntaxExpression)expr;
@@ -4541,7 +4632,7 @@ namespace Microsoft.Dafny {
var correctConstructor = FunctionCall(pat.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, rhs);
if (ctor.EnclosingDatatype.Ctors.Count == 1) {
// There is only one constructor, so the value must have been constructed by it; might as well assume that here.
- builder.Add(new Bpl.AssumeCmd(pat.tok, correctConstructor));
+ builder.Add(TrAssumeCmd(pat.tok, correctConstructor));
} else {
builder.Add(Assert(pat.tok, correctConstructor, string.Format("RHS is not certain to look like the pattern '{0}'", ctor.Name)));
}
@@ -4588,7 +4679,11 @@ namespace Microsoft.Dafny {
/// like it. This is useful in function postconditions, where the result of the function is
/// syntactically given as what looks like a recursive call with the same arguments.
/// "DoReadsChecks" indicates whether or not to perform reads checks. If so, the generated code
- /// will make references to $_Frame.
+ /// will make references to $_Frame. If "saveReadsChecks" is true, then the reads checks will
+ /// be recorded but postponsed. In particular, CheckWellformed will append to .Locals a list of
+ /// fresh local variables and will append to .Assert assertions with appropriate error messages
+ /// that can be used later. As a convenience, the ProcessSavedReadsChecks will make use of .Locals
+ /// and .Asserts (and AssignLocals) and update a given StmtListBuilder.
/// </summary>
private class WFOptions
{
@@ -4602,6 +4697,7 @@ namespace Microsoft.Dafny {
}
public WFOptions(Function selfCallsAllowance, bool doReadsChecks, bool saveReadsChecks = false) {
+ Contract.Requires(!saveReadsChecks || doReadsChecks); // i.e., saveReadsChecks ==> doReadsChecks
SelfCallsAllowance = selfCallsAllowance;
DoReadsChecks = doReadsChecks;
if (saveReadsChecks) {
@@ -4635,6 +4731,24 @@ namespace Microsoft.Dafny {
);
}
}
+
+ public void ProcessSavedReadsChecks(List<Variable> locals, StmtListBuilder builderInitializationArea, StmtListBuilder builder) {
+ Contract.Requires(locals != null);
+ Contract.Requires(builderInitializationArea != null);
+ Contract.Requires(builder != null);
+ Contract.Requires(Locals != null && Asserts != null); // ProcessSavedReadsChecks should be called only if the constructor was called with saveReadsChecks
+
+ // var b$reads_guards#0 : bool ...
+ locals.AddRange(Locals);
+ // b$reads_guards#0 := true ...
+ foreach (var cmd in AssignLocals) {
+ builderInitializationArea.Add(cmd);
+ }
+ // assert b$reads_guards#0; ...
+ foreach (var a in Asserts) {
+ builder.Add(a);
+ }
+ }
}
void TrStmt_CheckWellformed(Expression expr, Bpl.StmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, bool subsumption) {
@@ -4642,6 +4756,7 @@ namespace Microsoft.Dafny {
Contract.Requires(builder != null);
Contract.Requires(locals != null);
Contract.Requires(etran != null);
+ Contract.Requires(predef != null);
Bpl.QKeyValue kv;
if (subsumption) {
@@ -4653,10 +4768,121 @@ namespace Microsoft.Dafny {
kv = new Bpl.QKeyValue(expr.tok, "subsumption", args, null);
}
CheckWellformed(expr, new WFOptions(kv), locals, builder, etran);
- builder.Add(new Bpl.AssumeCmd(expr.tok, CanCallAssumption(expr, etran)));
+ builder.Add(TrAssumeCmd(expr.tok, CanCallAssumption(expr, etran)));
+ }
+
+ void CheckWellformedAndAssume(Expression expr, WFOptions options, List<Variable> locals, Bpl.StmtListBuilder builder, ExpressionTranslator etran) {
+ Contract.Requires(expr != null);
+ Contract.Requires(expr.Type != null && expr.Type.IsBoolType);
+ Contract.Requires(options != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(builder != null);
+ Contract.Requires(etran != null);
+ Contract.Requires(predef != null);
+ if (expr is BinaryExpr) {
+ var e = (BinaryExpr)expr;
+ switch (e.ResolvedOp) {
+ case BinaryExpr.ResolvedOpcode.And:
+ // WF[e0]; assume e0; WF[e1]; assume e1;
+ CheckWellformedAndAssume(e.E0, options, locals, builder, etran);
+ CheckWellformedAndAssume(e.E1, options, locals, builder, etran);
+ return;
+ case BinaryExpr.ResolvedOpcode.Imp: {
+ // if (*) {
+ // WF[e0]; assume e0; WF[e1]; assume e1;
+ // } else {
+ // assume e0 ==> e1;
+ // }
+ var bAnd = new Bpl.StmtListBuilder();
+ CheckWellformedAndAssume(e.E0, options, locals, bAnd, etran);
+ CheckWellformedAndAssume(e.E1, options, locals, bAnd, etran);
+ var bImp = new Bpl.StmtListBuilder();
+ bImp.Add(TrAssumeCmd(expr.tok, etran.TrExpr(expr)));
+ builder.Add(new Bpl.IfCmd(expr.tok, null, bAnd.Collect(expr.tok), null, bImp.Collect(expr.tok)));
+ }
+ return;
+ case BinaryExpr.ResolvedOpcode.Or: {
+ // if (*) {
+ // WF[e0]; assume e0;
+ // } else {
+ // assume !e0;
+ // WF[e1]; assume e1;
+ // }
+ var b0 = new Bpl.StmtListBuilder();
+ CheckWellformedAndAssume(e.E0, options, locals, b0, etran);
+ var b1 = new Bpl.StmtListBuilder();
+ b1.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Not(etran.TrExpr(e.E0))));
+ CheckWellformedAndAssume(e.E1, options, locals, b1, etran);
+ builder.Add(new Bpl.IfCmd(expr.tok, null, b0.Collect(expr.tok), null, b1.Collect(expr.tok)));
+ }
+ return;
+ default:
+ break;
+ }
+ } else if (expr is ITEExpr) {
+ var e = (ITEExpr)expr;
+ // if (*) {
+ // WF[test]; assume test;
+ // WF[thn]; assume thn;
+ // } else {
+ // assume !test;
+ // WF[els]; assume els;
+ // }
+ var bThn = new Bpl.StmtListBuilder();
+ CheckWellformedAndAssume(e.Test, options, locals, bThn, etran);
+ CheckWellformedAndAssume(e.Thn, options, locals, bThn, etran);
+ var bEls = new Bpl.StmtListBuilder();
+ bEls.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Not(etran.TrExpr(e.Test))));
+ CheckWellformedAndAssume(e.Els, options, locals, bEls, etran);
+ builder.Add(new Bpl.IfCmd(expr.tok, null, bThn.Collect(expr.tok), null, bEls.Collect(expr.tok)));
+ return;
+ } else if (expr is QuantifierExpr) {
+ var e = (QuantifierExpr)expr;
+ // For (Q x :: body(x)), introduce fresh local variable x'. Then:
+ // havoc x'
+ // WF[body(x')]; assume body(x');
+ // If the quantifier is universal, then continue as:
+ // assume (\forall x :: body(x));
+ // Create local variables corresponding to the type arguments:
+
+ var typeArgumentCopies = Map(e.TypeArgs, tp => e.Refresh(tp, CurrentIdGenerator));
+ var typeMap = Util.Dict(e.TypeArgs, Map(typeArgumentCopies, tp => (Type)new UserDefinedType(tp)));
+ var newLocals = Map(typeArgumentCopies, tp => new Bpl.LocalVariable(tp.tok, new TypedIdent(tp.tok, nameTypeParam(tp), predef.Ty)));
+ locals.AddRange(newLocals);
+ // Create local variables corresponding to the bound variables:
+ var substMap = SetupBoundVarsAsLocals(e.BoundVars, builder, locals, etran, typeMap);
+ // Get the body of the quantifier and suitably substitute for the type variables and bound variables
+ var body = Substitute(e.LogicalBody(true), null, substMap, typeMap);
+ CheckWellformedAndAssume(body, options, locals, builder, etran);
+
+ if (e is ForallExpr) {
+ // Although we do the WF check on the original quantifier, we assume the split one.
+ // This ensures that cases like forall x :: x != null && f(x.a) do not fail to verify.
+ builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(e.SplitQuantifierExpression ?? e)));
+ }
+ return;
+ }
+
+ // resort to the behavior of simply checking well-formedness followed by assuming the translated expression
+ CheckWellformed(expr, options, locals, builder, etran);
+
+ // NOTE: If the CheckWellformed call above found a split quantifier, it ignored
+ // the splitting and proceeded to decompose the full quantifier as
+ // normal. This call to TrExpr, on the other hand, will indeed use the
+ // split quantifier.
+ builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(expr)));
}
+ /// <summary>
+ /// Check the well-formedness of "expr" (but don't leave hanging around any assumptions that affect control flow)
+ /// </summary>
void CheckWellformed(Expression expr, WFOptions options, List<Variable> locals, Bpl.StmtListBuilder builder, ExpressionTranslator etran) {
+ Contract.Requires(expr != null);
+ Contract.Requires(options != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(builder != null);
+ Contract.Requires(etran != null);
+ Contract.Requires(predef != null);
CheckWellformedWithResult(expr, options, null, null, locals, builder, etran);
}
@@ -4703,7 +4929,7 @@ namespace Microsoft.Dafny {
var correctConstructor = FunctionCall(e.tok, dtor.EnclosingCtor.QueryField.FullSanitizedName, Bpl.Type.Bool, etran.TrExpr(e.Obj));
if (dtor.EnclosingCtor.EnclosingDatatype.Ctors.Count == 1) {
// There is only one constructor, so the value must be been constructed by it; might as well assume that here.
- builder.Add(new Bpl.AssumeCmd(expr.tok, correctConstructor));
+ builder.Add(TrAssumeCmd(expr.tok, correctConstructor));
} else {
builder.Add(Assert(expr.tok, correctConstructor,
string.Format("destructor '{0}' can only be applied to datatype values constructed by '{1}'", dtor.Name, dtor.EnclosingCtor.Name)));
@@ -4759,7 +4985,8 @@ namespace Microsoft.Dafny {
var range = BplAnd(Bpl.Expr.Le(lowerBound, i), Bpl.Expr.Lt(i, upperBound));
var fieldName = FunctionCall(e.tok, BuiltinFunction.IndexField, null, i);
var allowedToRead = Bpl.Expr.SelectTok(e.tok, etran.TheFrame(e.tok), seq, fieldName);
- var qq = new Bpl.ForallExpr(e.tok, new List<Variable> { iVar }, Bpl.Expr.Imp(range, allowedToRead));
+ var trigger = BplTrigger(allowedToRead); // Note, the assertion we're about to produce only seems useful in the check-only mode (that is, with subsumption 0), but if it were to be assumed, we'll use this entire RHS as the trigger
+ var qq = new Bpl.ForallExpr(e.tok, new List<Variable> { iVar }, trigger, BplImp(range, allowedToRead));
options.AssertSink(this, builder)(expr.tok, qq, "insufficient reads clause to read the indicated range of array elements", options.AssertKv);
}
}
@@ -4767,16 +4994,17 @@ namespace Microsoft.Dafny {
MultiSelectExpr e = (MultiSelectExpr)expr;
CheckWellformed(e.Array, options, locals, builder, etran);
Bpl.Expr array = etran.TrExpr(e.Array);
- int i = 0;
- foreach (Expression idx in e.Indices) {
+ for (int idxId = 0; idxId < e.Indices.Count; idxId++) {
+ var idx = e.Indices[idxId];
CheckWellformed(idx, options, locals, builder, etran);
- Bpl.Expr index = etran.TrExpr(idx);
- Bpl.Expr lower = Bpl.Expr.Le(Bpl.Expr.Literal(0), index);
- Bpl.Expr length = ArrayLength(idx.tok, array, e.Indices.Count, i);
- Bpl.Expr upper = Bpl.Expr.Lt(index, length);
- builder.Add(Assert(idx.tok, Bpl.Expr.And(lower, upper), "index " + i + " out of range", options.AssertKv));
- i++;
+ var index = etran.TrExpr(idx);
+ var lower = Bpl.Expr.Le(Bpl.Expr.Literal(0), index);
+ var length = ArrayLength(idx.tok, array, e.Indices.Count, idxId);
+ var upper = Bpl.Expr.Lt(index, length);
+ var tok = idx is IdentifierExpr ? e.tok : idx.tok; // TODO: Reusing the token of an identifier expression would underline its definition. but this is still not perfect.
+
+ builder.Add(Assert(tok, Bpl.Expr.And(lower, upper), String.Format("index {0} out of range", idxId), options.AssertKv));
}
} else if (expr is SeqUpdateExpr) {
SeqUpdateExpr e = (SeqUpdateExpr)expr;
@@ -4853,7 +5081,7 @@ namespace Microsoft.Dafny {
builder.Add(Assert(expr.tok, precond, "possible violation of function precondition"));
if (options.DoReadsChecks) {
- Type objset = new SetType(new ObjectType());
+ Type objset = new SetType(true, new ObjectType());
Expression wrap = new BoogieWrapper(
FunctionCall(e.tok, Reads(arity), TrType(objset), args),
objset);
@@ -4894,8 +5122,11 @@ namespace Microsoft.Dafny {
CheckSubrange(ee.tok, etran.TrExpr(ee), et, builder);
Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(p.tok, lhs, CondApplyBox(p.tok, etran.TrExpr(ee), cce.NonNull(ee.Type), et));
builder.Add(cmd);
- builder.Add(new Bpl.CommentCmd("assume allocatedness for argument to function"));
- builder.Add(new Bpl.AssumeCmd(e.Args[i].tok, MkIsAlloc(lhs, et, etran.HeapExpr)));
+ if (!etran.UsesOldHeap) {
+ // the argument can't be assumed to be allocated for the old heap
+ builder.Add(new Bpl.CommentCmd("assume allocatedness for argument to function"));
+ builder.Add(TrAssumeCmd(e.Args[i].tok, MkIsAlloc(lhs, et, etran.HeapExpr)));
+ }
}
// Check that every parameter is available in the state in which the function is invoked; this means checking that it has
// the right type and is allocated. These checks usually hold trivially, on account of that the Dafny language only gives
@@ -4933,7 +5164,7 @@ namespace Microsoft.Dafny {
}
if (options.AssertKv == null) {
// assume only if no given assert attribute is given
- builder.Add(new Bpl.AssumeCmd(expr.tok, etran.TrExpr(precond)));
+ builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(precond)));
}
}
if (options.DoReadsChecks) {
@@ -4985,8 +5216,8 @@ namespace Microsoft.Dafny {
Contract.Assert(false); // unexpected CoCallResolution
goto case FunctionCallExpr.CoCallResolution.No; // please the compiler
}
- CheckCallTermination(expr.tok, contextDecreases, calleeDecreases, allowance, e.Receiver, substMap, etran, etran, builder,
- codeContext.InferredDecreases, hint);
+ CheckCallTermination(expr.tok, contextDecreases, calleeDecreases, allowance, e.Receiver, substMap, e.TypeArgumentSubstitutions,
+ etran, etran, builder, codeContext.InferredDecreases, hint);
}
}
@@ -4994,7 +5225,7 @@ namespace Microsoft.Dafny {
Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, e.Function.FullSanitizedName + "#canCall", Bpl.Type.Bool);
List<Bpl.Expr> args = etran.FunctionInvocationArguments(e, null);
Bpl.Expr canCallFuncAppl = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);
- builder.Add(new Bpl.AssumeCmd(expr.tok, allowance == null ? canCallFuncAppl : Bpl.Expr.Or(allowance, canCallFuncAppl)));
+ builder.Add(TrAssumeCmd(expr.tok, allowance == null ? canCallFuncAppl : Bpl.Expr.Or(allowance, canCallFuncAppl)));
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
@@ -5091,10 +5322,11 @@ namespace Microsoft.Dafny {
var rIe = new Bpl.IdentifierExpr(pat.tok, r);
CheckWellformedWithResult(e.RHSs[i], options, rIe, pat.Expr.Type, locals, builder, etran);
CheckCasePatternShape(pat, rIe, builder);
- builder.Add(new Bpl.AssumeCmd(pat.tok, Bpl.Expr.Eq(etran.TrExpr(Substitute(pat.Expr, null, substMap)), rIe)));
+ builder.Add(TrAssumeCmd(pat.tok, Bpl.Expr.Eq(etran.TrExpr(Substitute(pat.Expr, null, substMap)), rIe)));
}
CheckWellformedWithResult(Substitute(e.Body, null, substMap), options, result, resultType, locals, builder, etran);
result = null;
+
} else {
// CheckWellformed(var b :| RHS(b); Body(b)) =
// var b where typeAntecedent;
@@ -5121,7 +5353,7 @@ namespace Microsoft.Dafny {
w = BplOr(body, w);
}
builder.Add(Assert(e.tok, w, "cannot establish the existence of LHS values that satisfy the such-that predicate"));
- builder.Add(new Bpl.AssumeCmd(e.tok, etran.TrExpr(rhs)));
+ builder.Add(TrAssumeCmd(e.tok, etran.TrExpr(rhs)));
var letBody = Substitute(e.Body, null, substMap);
CheckWellformed(letBody, options, locals, builder, etran);
if (e.Constraint_Bounds != null) {
@@ -5129,9 +5361,9 @@ namespace Microsoft.Dafny {
var substMap_prime = SetupBoundVarsAsLocals(lhsVars, builder, locals, etran);
var rhs_prime = Substitute(e.RHSs[0], null, substMap_prime);
var letBody_prime = Substitute(e.Body, null, substMap_prime);
- builder.Add(new Bpl.AssumeCmd(e.tok, CanCallAssumption(rhs_prime, etran)));
- builder.Add(new Bpl.AssumeCmd(e.tok, etran.TrExpr(rhs_prime)));
- builder.Add(new Bpl.AssumeCmd(e.tok, CanCallAssumption(letBody_prime, etran)));
+ builder.Add(TrAssumeCmd(e.tok, CanCallAssumption(rhs_prime, etran)));
+ builder.Add(TrAssumeCmd(e.tok, etran.TrExpr(rhs_prime)));
+ builder.Add(TrAssumeCmd(e.tok, CanCallAssumption(letBody_prime, etran)));
var eq = Expression.CreateEq(letBody, letBody_prime, e.Body.Type);
builder.Add(Assert(e.tok, etran.TrExpr(eq), "to be compilable, the value of a let-such-that expression must be uniquely determined"));
}
@@ -5140,11 +5372,11 @@ namespace Microsoft.Dafny {
Contract.Assert(resultType != null);
var bResult = etran.TrExpr(letBody);
CheckSubrange(letBody.tok, bResult, resultType, builder);
- builder.Add(new Bpl.AssumeCmd(letBody.tok, Bpl.Expr.Eq(result, bResult)));
- builder.Add(new Bpl.AssumeCmd(letBody.tok, CanCallAssumption(letBody, etran)));
+ builder.Add(TrAssumeCmd(letBody.tok, Bpl.Expr.Eq(result, bResult)));
+ builder.Add(TrAssumeCmd(letBody.tok, CanCallAssumption(letBody, etran)));
builder.Add(new CommentCmd("CheckWellformedWithResult: Let expression"));
- builder.Add(new Bpl.AssumeCmd(letBody.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));
- builder.Add(new Bpl.AssumeCmd(letBody.tok, MkIs(result, resultType)));
+ builder.Add(TrAssumeCmd(letBody.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));
+ builder.Add(TrAssumeCmd(letBody.tok, MkIs(result, resultType)));
result = null;
}
}
@@ -5162,6 +5394,9 @@ namespace Microsoft.Dafny {
var q = e as QuantifierExpr;
var lam = e as LambdaExpr;
+ // This is a WF check, so we look at the original quantifier, not the split one.
+ // This ensures that cases like forall x :: x != null && f(x.a) do not fail to verify.
+
var typeMap = new Dictionary<TypeParameter, Type>();
var copies = new List<TypeParameter>();
if (q != null) {
@@ -5179,7 +5414,6 @@ namespace Microsoft.Dafny {
var newEtran = etran;
builder.Add(new Bpl.CommentCmd("Begin Comprehension WF check"));
BplIfIf(e.tok, lam != null, null, builder, newBuilder => {
-
if (lam != null) {
// Havoc heap, unless oneShot
if (!lam.OneShot) {
@@ -5200,21 +5434,9 @@ namespace Microsoft.Dafny {
// Check frame WF and that it read covers itself
newOptions = new WFOptions(options.SelfCallsAllowance, true /* check reads clauses */, true /* delay reads checks */);
-
CheckFrameWellFormed(newOptions, reads, locals, newBuilder, newEtran);
-
// new options now contains the delayed reads checks
- locals.AddRange(newOptions.Locals);
- // assign locals to true, but at a scope above
- Contract.Assert(newBuilder != builder);
- foreach (var a in newOptions.AssignLocals) {
- builder.Add(a);
- }
-
- // add asserts to the current builder (right after frame WF)
- foreach (var a in newOptions.Asserts) {
- newBuilder.Add(a);
- }
+ newOptions.ProcessSavedReadsChecks(locals, builder, newBuilder);
// continue doing reads checks, but don't delay them
newOptions = new WFOptions(options.SelfCallsAllowance, true, false);
@@ -5261,7 +5483,7 @@ namespace Microsoft.Dafny {
Bpl.Expr src = etran.TrExpr(me.Source);
Bpl.IfCmd ifCmd = null;
StmtListBuilder elsBldr = new StmtListBuilder();
- elsBldr.Add(new Bpl.AssumeCmd(expr.tok, Bpl.Expr.False));
+ elsBldr.Add(TrAssumeCmd(expr.tok, Bpl.Expr.False));
StmtList els = elsBldr.Collect(expr.tok);
foreach (var missingCtor in me.MissingCases) {
// havoc all bound variables
@@ -5315,11 +5537,11 @@ namespace Microsoft.Dafny {
Contract.Assert(resultType != null);
var bResult = etran.TrExpr(expr);
CheckSubrange(expr.tok, bResult, resultType, builder);
- builder.Add(new Bpl.AssumeCmd(expr.tok, Bpl.Expr.Eq(result, bResult)));
- builder.Add(new Bpl.AssumeCmd(expr.tok, CanCallAssumption(expr, etran)));
+ builder.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Eq(result, bResult)));
+ builder.Add(TrAssumeCmd(expr.tok, CanCallAssumption(expr, etran)));
builder.Add(new CommentCmd("CheckWellformedWithResult: any expression"));
- builder.Add(new Bpl.AssumeCmd(expr.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));
- builder.Add(new Bpl.AssumeCmd(expr.tok, MkIs(result, resultType)));
+ builder.Add(TrAssumeCmd(expr.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));
+ builder.Add(TrAssumeCmd(expr.tok, MkIs(result, resultType)));
}
}
@@ -5464,7 +5686,7 @@ namespace Microsoft.Dafny {
tyargs.Add(TypeToTy(fm.Type));
}
tyargs.Add(TypeToTy(f.ResultType));
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
Bpl.Expr ly; vars.Add(BplBoundVar("$ly", predef.LayerType, out ly)); args.Add(ly);
formals.Add(BplFormalVar(null, predef.LayerType, true));
}
@@ -5494,14 +5716,24 @@ namespace Microsoft.Dafny {
var bvars = new List<Bpl.Variable>();
var lhs_args = new List<Bpl.Expr>();
var rhs_args = new List<Bpl.Expr>();
-
+ var func_vars = new List<Bpl.Variable>();
+ var func_args = new List<Bpl.Expr>();
+ var boxed_func_args = new List<Bpl.Expr>();
+
var idGen = f.IdGenerator.NestedFreshIdGenerator("$fh$");
foreach (var fm in f.Formals) {
- var fe = BplBoundVar(idGen.FreshId("x#"), predef.BoxType, bvars);
+ string fm_name = idGen.FreshId("x#");
+ // Box and its [Unbox]args
+ var fe = BplBoundVar(fm_name, predef.BoxType, bvars);
lhs_args.Add(fe);
var be = UnboxIfBoxed(fe, fm.Type);
rhs_args.Add(be);
rhs_dict[fm] = new BoogieWrapper(be, fm.Type);
+ // args and its [Box]args
+ var arg = BplBoundVar(fm_name, TrType(fm.Type), func_vars);
+ func_args.Add(arg);
+ var boxed = BoxIfUnboxed(arg, fm.Type);
+ boxed_func_args.Add(boxed);
}
var h = BplBoundVar("$heap", predef.HeapType, vars);
@@ -5524,7 +5756,6 @@ namespace Microsoft.Dafny {
{
// Requires(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, arg1, ..., argN)
// = F#Requires(Ty1, .., TyN, Layer, Heap, self, [Unbox] arg1, .., [Unbox] argN)
- // || Scramble(...)
var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(args));
var lhs = FunctionCall(f.tok, Requires(arity), Bpl.Type.Bool, Concat(tyargs, Cons(fhandle, Cons(h, lhs_args))));
@@ -5533,9 +5764,7 @@ namespace Microsoft.Dafny {
// In case this is the /requires/ or /reads/ function, then there is no precondition
rhs = Bpl.Expr.True;
} else {
- rhs = BplOr(
- FunctionCall(f.tok, RequiresName(f), Bpl.Type.Bool, Concat(SnocSelf(Snoc(args, h)), rhs_args)),
- MakeScrambler(f.tok, f.FullSanitizedName + "#lessReq", Concat(vars, bvars)));
+ rhs = FunctionCall(f.tok, RequiresName(f), Bpl.Type.Bool, Concat(SnocSelf(Snoc(args, h)), rhs_args));
}
sink.AddTopLevelDeclaration(new Axiom(f.tok,
@@ -5547,7 +5776,7 @@ namespace Microsoft.Dafny {
// = $Frame_F(args...)
var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(args));
- Bpl.Expr lhs_inner = FunctionCall(f.tok, Reads(arity), TrType(new SetType(new ObjectType())), Concat(tyargs, Cons(fhandle, Cons(h, lhs_args))));
+ Bpl.Expr lhs_inner = FunctionCall(f.tok, Reads(arity), TrType(new SetType(true, new ObjectType())), Concat(tyargs, Cons(fhandle, Cons(h, lhs_args))));
Bpl.Expr bx; var bxVar = BplBoundVar("$bx", predef.BoxType, out bx);
Bpl.Expr unboxBx = FunctionCall(f.tok, BuiltinFunction.Unbox, predef.RefType, bx);
@@ -5559,17 +5788,21 @@ namespace Microsoft.Dafny {
sink.AddTopLevelDeclaration(new Axiom(f.tok,
BplForall(Cons(bxVar, Concat(vars, bvars)), BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs))));
}
- }
- return name;
- }
- public Bpl.Expr MakeScrambler(IToken tk, string name, List<Variable> bvars) {
- var f = new Bpl.Function(tk, name,
- bvars.ConvertAll(bv => (Bpl.Variable)BplFormalVar(null, bv.TypedIdent.Type, true)),
- BplFormalVar(null, Bpl.Type.Bool, false));
+ {
+ // F(Ty1, .., TyN, Layer, Heap, self, arg1, .., argN)
+ // = [Unbox]Apply1(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, [Box]arg1, ..., [Box]argN)
- sink.AddTopLevelDeclaration(f);
- return FunctionCall(tk, name, Bpl.Type.Bool, bvars.ConvertAll(bv => (Bpl.Expr)new Bpl.IdentifierExpr(tk, bv)));
+ var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(args));
+ var lhs = FunctionCall(f.tok, f.FullSanitizedName, TrType(f.ResultType), Concat(SnocSelf(Snoc(args, h)), func_args));
+ var rhs = FunctionCall(f.tok, Apply(arity), TrType(f.ResultType), Concat(tyargs, Cons(fhandle, Cons(h, boxed_func_args))));
+ var rhs_unboxed = UnboxIfBoxed(rhs, f.ResultType);
+
+ sink.AddTopLevelDeclaration(new Axiom(f.tok,
+ BplForall(Concat(vars, func_vars), BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs_unboxed))));
+ }
+ }
+ return name;
}
private void AddArrowTypeAxioms(ArrowTypeDecl ad) {
@@ -5584,7 +5817,7 @@ namespace Microsoft.Dafny {
// [Heap, Box, ..., Box] Bool
var requires_ty = new Bpl.MapType(tok, new List<Bpl.TypeVariable>(), map_args, Bpl.Type.Bool);
// Set Box
- var objset_ty = TrType(new SetType(new ObjectType()));
+ var objset_ty = TrType(new SetType(true, new ObjectType()));
// [Heap, Box, ..., Box] (Set Box)
var reads_ty = new Bpl.MapType(tok, new List<Bpl.TypeVariable>(), map_args, objset_ty);
@@ -5617,11 +5850,9 @@ namespace Microsoft.Dafny {
{
// forall t1, .., tN+1 : Ty, p: [Heap, Box, ..., Box] Box, heap : Heap, b1, ..., bN : Box
- // :: RequriesN(...) ==> ApplyN(t1, .. tN+1, HandleN(h, r, rd), heap, b1, ..., bN) = h[heap, b1, ..., bN]
- //
- // no precondition for these, but:
- // for requires, we add: RequiresN(...) <== r[heap, b1, ..., bN]
- // for reads, we could: ReadsN(...)[bx] ==> rd[heap, b1, ..., bN][bx] , but we don't
+ // :: ApplyN(t1, .. tN+1, HandleN(h, r, rd), heap, b1, ..., bN) == h[heap, b1, ..., bN]
+ // :: RequiresN(t1, .. tN+1, HandleN(h, r, rd), heap, b1, ..., bN) <== r[heap, b1, ..., bN]
+ // :: ReadsN(t1, .. tN+1, HandleN(h, r, rd), heap, b1, ..., bN) == rd[heap, b1, ..., bN]
Action<string, Bpl.Type, string, Bpl.Type, string, Bpl.Type> SelectorSemantics = (selector, selectorTy, selectorVar, selectorVarTy, precond, precondTy) => {
Contract.Assert((precond == null) == (precondTy == null));
var bvars = new List<Bpl.Variable>();
@@ -5722,7 +5953,7 @@ namespace Microsoft.Dafny {
var h0 = BplBoundVar("h0", predef.HeapType, bvars);
var h1 = BplBoundVar("h1", predef.HeapType, bvars);
- var heapSucc = FunctionCall(tok, BuiltinFunction.HeapSucc, null, h0, h1);
+ var heapSucc = HeapSucc(h0, h1);
var goodHeaps = BplAnd(
FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h0),
FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h1));
@@ -5746,15 +5977,14 @@ namespace Microsoft.Dafny {
var fld = BplBoundVar("fld", predef.FieldName(tok, a), ivars);
var inner_forall = new Bpl.ForallExpr(tok, Singleton(a), ivars, BplImp(
- BplAnd(new List<Expr> {
+ BplAnd(
Bpl.Expr.Neq(o, predef.Null),
- IsAlloced(tok, h0, o),
- IsAlloced(tok, h1, o),
+ // Note, the MkIsAlloc conjunct of "isness" implies that everything in the reads frame is allocated in "h0", which by HeapSucc(h0,h1) also implies the frame is allocated in "h1"
new Bpl.NAryExpr(tok, new Bpl.MapSelect(tok, 1), new List<Bpl.Expr> {
FunctionCall(tok, Reads(ad.Arity), objset_ty, Concat(types, Cons(f, Cons(hN, boxes)))),
FunctionCall(tok, BuiltinFunction.Box, null, o)
})
- }),
+ ),
Bpl.Expr.Eq(ReadHeap(tok, h0, o, fld), ReadHeap(tok, h1, o, fld))));
Func<Bpl.Expr, Bpl.Expr> fn = h => FunctionCall(tok, fname, Bpl.Type.Bool, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
@@ -5775,42 +6005,86 @@ namespace Microsoft.Dafny {
AddFrameForFunction(h1, Apply(ad.Arity));
}
- // consequence axiom
+ // $Is and $IsAlloc axioms
/*
-
- forall t0..tN+1 : Ty, h : Heap, f : Handle, bx1 .. bxN : Box,
- GoodHeap(h)
- && Is&IsAllocBox(bxI, tI, h)
- && Is&IsAlloc(f, Func(t1,..,tN, tN+1), h)
- ==> Is&IsAllocBox(Apply(f,h0,bxs)))
-
- */
+ axiom (forall f: HandleType, t0: Ty, t1: Ty ::
+ { $Is(f, Tclass._System.___hFunc1(t0, t1)) }
+ $Is(f, Tclass._System.___hFunc1(t0, t1))
+ <==> (forall h: Heap, bx0: Box ::
+ { Apply1(t0, t1, f, h, bx0) }
+ $IsGoodHeap(h) && $IsBox(bx0, t0)
+ && precondition of f(bx0) holds in h
+ ==> $IsBox(Apply1(t0, t1, f, h, bx0), t1)));
+ */
{
- var bvars = new List<Bpl.Variable>();
-
- var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar("t" + i, predef.Ty, bvars));
-
- var h = BplBoundVar("h", predef.HeapType, bvars);
+ var bvarsOuter = new List<Bpl.Variable>();
+ var f = BplBoundVar("f", predef.HandleType, bvarsOuter);
+ var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar("t" + i, predef.Ty, bvarsOuter));
+ var Is = MkIs(f, ClassTyCon(ad, types));
+
+ var bvarsInner = new List<Bpl.Variable>();
+ var h = BplBoundVar("h", predef.HeapType, bvarsInner);
+ var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar("bx" + i, predef.BoxType, bvarsInner));
var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);
+ var isBoxes = BplAnd(Map(Enumerable.Range(0, arity), i => MkIs(boxes[i], types[i], true)));
+ var pre = FunctionCall(tok, Requires(ad.Arity), predef.BoxType, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
+ var applied = FunctionCall(tok, Apply(ad.Arity), predef.BoxType, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
+ var applied_is = MkIs(applied, types[ad.Arity], true);
- var f = BplBoundVar("f", predef.HandleType, bvars);
- var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar("bx" + i, predef.BoxType, bvars));
-
- var isness = BplAnd(
- Snoc(Map(Enumerable.Range(0, arity), i =>
- BplAnd(MkIs(boxes[i], types[i], true),
- MkIsAlloc(boxes[i], types[i], h, true))),
- BplAnd(MkIs(f, ClassTyCon(ad, types)),
- MkIsAlloc(f, ClassTyCon(ad, types), h))));
+ sink.AddTopLevelDeclaration(new Axiom(tok,
+ BplForall(bvarsOuter, BplTrigger(Is),
+ BplIff(Is,
+ BplForall(bvarsInner, BplTrigger(applied),
+ BplImp(BplAnd(BplAnd(goodHeap, isBoxes), pre), applied_is))))));
+ }
+ /*
+ axiom (forall f: HandleType, t0: Ty, t1: Ty, h: Heap ::
+ { $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h) }
+ $IsGoodHeap(h)
+ ==>
+ (
+ $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h)
+ <==>
+ (forall bx0: Box ::
+ { Apply1(t0, t1, f, h, bx0) } { Reads1(t0, t1, f, h, bx0) }
+ $IsAllocBox(bx0, t0, h)
+ && precondition of f(bx0) holds in h
+ ==>
+ (everything in reads set of f(bx0) is allocated in h) &&
+ $IsAllocBox(Apply1(t0, t1, f, h, bx0), t1, h))
+ ));
+ */
+ {
+ var bvarsOuter = new List<Bpl.Variable>();
+ var f = BplBoundVar("f", predef.HandleType, bvarsOuter);
+ var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar("t" + i, predef.Ty, bvarsOuter));
+ var h = BplBoundVar("h", predef.HeapType, bvarsOuter);
+ var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);
+ var isAlloc = MkIsAlloc(f, ClassTyCon(ad, types), h);
+ var bvarsInner = new List<Bpl.Variable>();
+ var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar("bx" + i, predef.BoxType, bvarsInner));
+ var isAllocBoxes = BplAnd(Map(Enumerable.Range(0, arity), i => MkIsAlloc(boxes[i], types[i], h, true)));
+ var pre = FunctionCall(tok, Requires(ad.Arity), predef.BoxType, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
var applied = FunctionCall(tok, Apply(ad.Arity), predef.BoxType, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
+ var applied_isAlloc = MkIsAlloc(applied, types[ad.Arity], h, true);
- var applied_is = BplAnd(MkIs(applied, types[ad.Arity], true), MkIsAlloc(applied, types[ad.Arity], h, true));
+ // (forall r: ref :: {Reads1(t0, t1, f, h, bx0)[$Box(r)]} r != null && Reads1(t0, t1, f, h, bx0)[$Box(r)] ==> h[r, alloc])
+ var bvarsR = new List<Bpl.Variable>();
+ var r = BplBoundVar("r", predef.RefType, bvarsR);
+ var rNonNull = Bpl.Expr.Neq(r, predef.Null);
+ var reads = FunctionCall(tok, Reads(ad.Arity), predef.BoxType, Concat(types, Cons(f, Cons<Bpl.Expr>(h, boxes))));
+ var rInReads = Bpl.Expr.Select(reads, FunctionCall(tok, BuiltinFunction.Box, null, r));
+ var rAlloc = IsAlloced(tok, h, r);
+ var isAllocReads = BplForall(bvarsR, BplTrigger(rInReads), BplImp(BplAnd(rNonNull, rInReads), rAlloc));
sink.AddTopLevelDeclaration(new Axiom(tok,
- BplForall(bvars,
- new Bpl.Trigger(tok, true, new List<Bpl.Expr> {applied}),
- BplImp(BplAnd(goodHeap, isness), applied_is))));
+ BplForall(bvarsOuter, BplTrigger(isAlloc),
+ BplImp(goodHeap,
+ BplIff(isAlloc,
+ BplForall(bvarsInner,
+ new Bpl.Trigger(tok, true, new List<Bpl.Expr> { applied }, BplTrigger(reads)),
+ BplImp(BplAnd(isAllocBoxes, pre), BplAnd(isAllocReads, applied_isAlloc))))))));
}
}
}
@@ -5823,7 +6097,7 @@ namespace Microsoft.Dafny {
var inner_name = GetClass(td).TypedIdent.Name;
string name = "T" + inner_name;
// Create the type constructor
- {
+ if (td.Name != "object") { // the type constructor for "object" is in DafnyPrelude.bpl
Bpl.Variable tyVarOut = BplFormalVar(null, predef.Ty, false);
List<Bpl.Variable> args = new List<Bpl.Variable>(
Enumerable.Range(0, arity).Select(i =>
@@ -5998,8 +6272,10 @@ namespace Microsoft.Dafny {
// axiom (forall o: Ref :: 0 <= array.Length(o));
Bpl.BoundVariable oVar = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, "o", predef.RefType));
Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(f.tok, oVar);
- Bpl.Expr body = Bpl.Expr.Le(Bpl.Expr.Literal(0), new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(ff), new List<Bpl.Expr> { o }));
- Bpl.Expr qq = new Bpl.ForallExpr(f.tok, new List<Variable> { oVar }, body);
+ var rhs = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(ff), new List<Bpl.Expr> { o });
+ Bpl.Expr body = Bpl.Expr.Le(Bpl.Expr.Literal(0), rhs);
+ var trigger = BplTrigger(rhs);
+ Bpl.Expr qq = new Bpl.ForallExpr(f.tok, new List<Variable> { oVar }, trigger, body);
sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, qq));
}
}
@@ -6027,7 +6303,7 @@ namespace Microsoft.Dafny {
var typeParams = TrTypeParamDecls(f.TypeArgs);
var formals = new List<Variable>();
formals.AddRange(MkTyParamFormals(GetTypeParams(f)));
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType), true));
}
formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, "$heap", predef.HeapType), true));
@@ -6136,11 +6412,8 @@ namespace Microsoft.Dafny {
req.Add(Requires(p.E.tok, true, etran.TrExpr(p.E), null, comment));
comment = null;
} else {
- bool splitHappened; // we actually don't care
- foreach (var s in TrSplitExpr(p.E, etran, kind == MethodTranslationKind.InterModuleCall ? 0 : int.MaxValue, true /* kind == MethodTranslationKind.Implementation */, out splitHappened)) {
- if ((kind == MethodTranslationKind.IntraModuleCall || kind == MethodTranslationKind.CoCall) && RefinementToken.IsInherited(s.E.tok, currentModule)) {
- // this precondition was inherited into this module, so just ignore it
- } else if (s.IsOnlyChecked && bodyKind) {
+ foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {
+ if (s.IsOnlyChecked && bodyKind) {
// don't include in split
} else if (s.IsOnlyFree && !bodyKind) {
// don't include in split -- it would be ignored, anyhow
@@ -6159,8 +6432,7 @@ namespace Microsoft.Dafny {
if (p.IsFree && !DafnyOptions.O.DisallowSoundnessCheating) {
ens.Add(Ensures(p.E.tok, true, etran.TrExpr(p.E), null, null));
} else {
- bool splitHappened; // we actually don't care
- foreach (var s in TrSplitExpr(p.E, etran, kind == MethodTranslationKind.InterModuleCall ? 0 : int.MaxValue, true /* kind == MethodTranslationKind.Implementation */ , out splitHappened)) {
+ foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {
var post = s.E;
if (kind == MethodTranslationKind.Implementation && RefinementToken.IsInherited(s.E.tok, currentModule)) {
// this postcondition was inherited into this module, so make it into the form "$_reverifyPost ==> s.E"
@@ -6332,7 +6604,7 @@ namespace Microsoft.Dafny {
}
// Make the call
- builder.Add(new Bpl.CallCmd(method.tok, method.FullSanitizedName, ins, outs));
+ builder.Add(Call(method.tok, method.FullSanitizedName, ins, outs));
for (int i = 0; i < m.Outs.Count; i++) {
var bLhs = m.Outs[i];
@@ -6347,7 +6619,7 @@ namespace Microsoft.Dafny {
foreach (var p in m.Ens) {
bool splitHappened; // we actually don't care
foreach (var s in TrSplitExpr(p.E, etran, true, out splitHappened)) {
- var assert = new Bpl.AssertCmd(method.tok, s.E, ErrorMessageAttribute(s.E.tok, "This is the postcondition that may not hold."));
+ var assert = TrAssertCmd(method.tok, s.E, ErrorMessageAttribute(s.E.tok, "This is the postcondition that may not hold."));
assert.ErrorData = "Error: A postcondition of the refined method may not hold.";
builder.Add(assert);
}
@@ -6363,6 +6635,18 @@ namespace Microsoft.Dafny {
Reset();
}
+ private static CallCmd Call(IToken tok, string methodName, List<Expr> ins, List<Bpl.IdentifierExpr> outs) {
+ Contract.Requires(tok != null);
+ Contract.Requires(methodName != null);
+ Contract.Requires(ins != null);
+ Contract.Requires(outs != null);
+
+ CallCmd call;
+ call = new CallCmd(tok, methodName, ins, outs);
+ // CLEMENT enable this: call.ErrorData = "possible violation of function precondition";
+ return call;
+ }
+
private static QKeyValue ErrorMessageAttribute(IToken t, string error) {
var l = new List<object>(1);
l.Add(error);
@@ -6387,7 +6671,7 @@ namespace Microsoft.Dafny {
// parameters of the procedure
List<Variable> inParams = new List<Variable>();
Bpl.Formal layer;
- if (f.IsRecursive) {
+ if (f.IsFuelAware()) {
layer = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, "$ly", predef.LayerType), true);
inParams.Add(layer);
} else {
@@ -6576,7 +6860,7 @@ namespace Microsoft.Dafny {
// the frame condition, which is free since it is checked with every heap update and call
boilerplate.Add(new BoilerplateTriple(tok, true, FrameCondition(tok, modifiesClause, isGhostContext, etranPre, etran, etranMod), null, "frame condition"));
// HeapSucc(S1, S2) or HeapSuccGhost(S1, S2)
- Bpl.Expr heapSucc = FunctionCall(tok, isGhostContext ? BuiltinFunction.HeapSuccGhost : BuiltinFunction.HeapSucc, null, etranPre.HeapExpr, etran.HeapExpr);
+ Bpl.Expr heapSucc = HeapSucc(etranPre.HeapExpr, etran.HeapExpr, isGhostContext);
boilerplate.Add(new BoilerplateTriple(tok, true, heapSucc, null, "boilerplate"));
}
return boilerplate;
@@ -6696,7 +6980,7 @@ namespace Microsoft.Dafny {
} else if (type.IsDatatype || type is DatatypeProxy) {
return predef.DatatypeType;
} else if (type is SetType) {
- return predef.SetType(Token.NoToken, predef.BoxType);
+ return predef.SetType(Token.NoToken, ((SetType)type).Finite, predef.BoxType);
} else if (type is MultiSetType) {
return predef.MultiSetType(Token.NoToken, predef.BoxType);
} else if (type is MapType) {
@@ -6820,9 +7104,9 @@ namespace Microsoft.Dafny {
if (assertAsAssume || (RefinementToken.IsInherited(refinesToken, currentModule) && (codeContext == null || !codeContext.MustReverify))) {
// produce an assume instead
- return new Bpl.AssumeCmd(tok, condition, kv);
+ return TrAssumeCmd(tok, condition, kv);
} else {
- var cmd = new Bpl.AssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);
+ var cmd = TrAssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);
cmd.ErrorData = "Error: " + errorMessage;
return cmd;
}
@@ -6839,12 +7123,12 @@ namespace Microsoft.Dafny {
if (RefinementToken.IsInherited(refinesTok, currentModule) && (codeContext == null || !codeContext.MustReverify)) {
// produce a "skip" instead
- return new Bpl.AssumeCmd(tok, Bpl.Expr.True, kv);
+ return TrAssumeCmd(tok, Bpl.Expr.True, kv);
} else {
tok = ForceCheckToken.Unwrap(tok);
var args = new List<object>();
args.Add(Bpl.Expr.Literal(0));
- Bpl.AssertCmd cmd = new Bpl.AssertCmd(tok, condition, new Bpl.QKeyValue(tok, "subsumption", args, kv));
+ Bpl.AssertCmd cmd = TrAssertCmd(tok, condition, new Bpl.QKeyValue(tok, "subsumption", args, kv));
cmd.ErrorData = "Error: " + errorMessage;
return cmd;
}
@@ -6858,9 +7142,9 @@ namespace Microsoft.Dafny {
if (assertAsAssume || (RefinementToken.IsInherited(tok, currentModule) && (codeContext == null || !codeContext.MustReverify))) {
// produce an assume instead
- return new Bpl.AssumeCmd(tok, condition, kv);
+ return TrAssumeCmd(tok, condition, kv);
} else {
- var cmd = new Bpl.AssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);
+ var cmd = TrAssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);
cmd.ErrorData = "Error: " + errorMessage;
return cmd;
}
@@ -6883,6 +7167,7 @@ namespace Microsoft.Dafny {
{
Contract.Requires(tok != null);
Contract.Requires(condition != null);
+ Contract.Ensures(Contract.Result<Bpl.Requires>() != null);
Bpl.Requires req = new Bpl.Requires(ForceCheckToken.Unwrap(tok), free, condition, comment);
if (errorMessage != null) {
req.ErrorData = errorMessage;
@@ -6910,11 +7195,16 @@ namespace Microsoft.Dafny {
Contract.Requires(locals != null);
Contract.Requires(etran != null);
Contract.Requires(codeContext != null && predef != null);
+ Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));
if (stmt is PredicateStmt) {
+ var stmtBuilder = new Bpl.StmtListBuilder();
+ this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);
+ var defineFuel = DefineFuelConstant(stmt.Tok, stmt.Attributes, stmtBuilder, etran);
+ var b = defineFuel ? stmtBuilder : builder;
if (stmt is AssertStmt || DafnyOptions.O.DisallowSoundnessCheating) {
- AddComment(builder, stmt, "assert statement");
+ AddComment(b, stmt, "assert statement");
PredicateStmt s = (PredicateStmt)stmt;
- TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);
+ TrStmt_CheckWellformed(s.Expr, b, locals, etran, false);
IToken enclosingToken = null;
if (Attributes.Contains(stmt.Attributes, "prependAssertToken")) {
enclosingToken = stmt.Tok;
@@ -6923,22 +7213,32 @@ namespace Microsoft.Dafny {
var ss = TrSplitExpr(s.Expr, etran, true, out splitHappened);
if (!splitHappened) {
var tok = enclosingToken == null ? s.Expr.tok : new NestedToken(enclosingToken, s.Expr.tok);
- builder.Add(Assert(tok, etran.TrExpr(s.Expr), "assertion violation", stmt.Tok, etran.TrAttributes(stmt.Attributes, null)));
+ b.Add(Assert(tok, etran.TrExpr(s.Expr), "assertion violation", stmt.Tok, etran.TrAttributes(stmt.Attributes, null)));
} else {
foreach (var split in ss) {
if (split.IsChecked) {
var tok = enclosingToken == null ? split.E.tok : new NestedToken(enclosingToken, split.E.tok);
- builder.Add(AssertNS(tok, split.E, "assertion violation", stmt.Tok, etran.TrAttributes(stmt.Attributes, null))); // attributes go on every split
+ b.Add(AssertNS(tok, split.E, "assertion violation", stmt.Tok, etran.TrAttributes(stmt.Attributes, null))); // attributes go on every split
}
}
- builder.Add(new Bpl.AssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));
+ if (!defineFuel) {
+ b.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));
+ }
+ }
+ if (defineFuel) {
+ var ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), null, null);
+ builder.Add(ifCmd);
+ builder.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));
}
} else if (stmt is AssumeStmt) {
AddComment(builder, stmt, "assume statement");
AssumeStmt s = (AssumeStmt)stmt;
TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);
- builder.Add(new Bpl.AssumeCmd(stmt.Tok, etran.TrExpr(s.Expr), etran.TrAttributes(stmt.Attributes, null)));
+ // we need to increase fuel for quantifier expr and functions that contain quantifier expr in the assume context.
+ var existEtran = etran.LayerOffset(1);
+ builder.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr, null, existEtran, existEtran), etran.TrAttributes(stmt.Attributes, null)));
}
+ this.fuelContext = FuelSetting.PopFuelContext();
} else if (stmt is PrintStmt) {
AddComment(builder, stmt, "print statement");
PrintStmt s = (PrintStmt)stmt;
@@ -6994,7 +7294,7 @@ namespace Microsoft.Dafny {
var yc = new Bpl.IdentifierExpr(s.Tok, yieldCountVariable);
var incYieldCount = Bpl.Cmd.SimpleAssign(s.Tok, yc, Bpl.Expr.Binary(s.Tok, Bpl.BinaryOperator.Opcode.Add, yc, Bpl.Expr.Literal(1)));
builder.Add(incYieldCount);
- builder.Add(new Bpl.AssumeCmd(s.Tok, YieldCountAssumption(iter, etran)));
+ builder.Add(TrAssumeCmd(s.Tok, YieldCountAssumption(iter, etran)));
// assume $IsGoodHeap($Heap);
builder.Add(AssumeGoodHeap(s.Tok, etran));
// assert YieldEnsures[subst]; // where 'subst' replaces "old(E)" with "E" being evaluated in $_OldIterHeap
@@ -7013,7 +7313,7 @@ namespace Microsoft.Dafny {
builder.Add(AssertNS(yieldToken, split.E, "possible violation of yield-ensures condition", stmt.Tok, null));
}
}
- builder.Add(new Bpl.AssumeCmd(stmt.Tok, yeEtran.TrExpr(p.E)));
+ builder.Add(TrAssumeCmd(stmt.Tok, yeEtran.TrExpr(p.E)));
}
}
YieldHavoc(iter.tok, iter, builder, etran);
@@ -7078,7 +7378,7 @@ namespace Microsoft.Dafny {
builder.Add(Assert(s.Tok, w, "cannot establish the existence of LHS values that satisfy the such-that predicate"));
}
// End by doing the assume
- builder.Add(new Bpl.AssumeCmd(s.Tok, etran.TrExpr(s.Expr)));
+ builder.Add(TrAssumeCmd(s.Tok, etran.TrExpr(s.Expr)));
builder.Add(CaptureState(s)); // just do one capture state--here, at the very end (that is, don't do one before the assume)
} else if (stmt is UpdateStmt) {
@@ -7134,24 +7434,30 @@ namespace Microsoft.Dafny {
} else if (stmt is IfStmt) {
AddComment(builder, stmt, "if statement");
IfStmt s = (IfStmt)stmt;
- Bpl.Expr guard;
+ Expression guard;
if (s.Guard == null) {
guard = null;
} else {
- TrStmt_CheckWellformed(s.Guard, builder, locals, etran, true);
- guard = etran.TrExpr(s.Guard);
+ guard = s.IsExistentialGuard ? AlphaRename((ExistsExpr)s.Guard, "eg$", this) : s.Guard;
+ TrStmt_CheckWellformed(guard, builder, locals, etran, true);
}
Bpl.StmtListBuilder b = new Bpl.StmtListBuilder();
CurrentIdGenerator.Push();
+ if (s.IsExistentialGuard) {
+ var exists = (ExistsExpr)s.Guard; // the original (that is, not alpha-renamed) guard
+ IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran);
+ }
Bpl.StmtList thn = TrStmt2StmtList(b, s.Thn, locals, etran);
CurrentIdGenerator.Pop();
Bpl.StmtList els;
Bpl.IfCmd elsIf = null;
+ b = new Bpl.StmtListBuilder();
+ if (s.IsExistentialGuard) {
+ b.Add(TrAssumeCmd(guard.tok, Bpl.Expr.Not(etran.TrExpr(guard))));
+ }
if (s.Els == null) {
- b = new Bpl.StmtListBuilder();
els = b.Collect(s.Tok);
} else {
- b = new Bpl.StmtListBuilder();
els = TrStmt2StmtList(b, s.Els, locals, etran);
if (els.BigBlocks.Count == 1) {
Bpl.BigBlock bb = els.BigBlocks[0];
@@ -7161,7 +7467,7 @@ namespace Microsoft.Dafny {
}
}
}
- builder.Add(new Bpl.IfCmd(stmt.Tok, guard, thn, elsIf, els));
+ builder.Add(new Bpl.IfCmd(stmt.Tok, guard == null || s.IsExistentialGuard ? null : etran.TrExpr(guard), thn, elsIf, els));
} else if (stmt is AlternativeStmt) {
AddComment(builder, stmt, "alternative statement");
@@ -7171,6 +7477,8 @@ namespace Microsoft.Dafny {
} else if (stmt is WhileStmt) {
AddComment(builder, stmt, "while statement");
+ this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);
+ DefineFuelConstant(stmt.Tok, stmt.Attributes, builder, etran);
var s = (WhileStmt)stmt;
BodyTranslator bodyTr = null;
if (s.Body != null) {
@@ -7181,7 +7489,7 @@ namespace Microsoft.Dafny {
};
}
TrLoop(s, s.Guard, bodyTr, builder, locals, etran);
-
+ this.fuelContext = FuelSetting.PopFuelContext();
} else if (stmt is AlternativeLoopStmt) {
AddComment(builder, stmt, "alternative loop statement");
var s = (AlternativeLoopStmt)stmt;
@@ -7209,11 +7517,11 @@ namespace Microsoft.Dafny {
// havoc $Heap;
builder.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));
// assume $HeapSucc(preModifyHeap, $Heap); OR $HeapSuccGhost
- builder.Add(new Bpl.AssumeCmd(s.Tok, FunctionCall(s.Tok, s.IsGhost ? BuiltinFunction.HeapSuccGhost : BuiltinFunction.HeapSucc, null, preModifyHeap, etran.HeapExpr)));
+ builder.Add(TrAssumeCmd(s.Tok, HeapSucc(preModifyHeap, etran.HeapExpr, s.IsGhost)));
// assume nothing outside the frame was changed
var etranPreLoop = new ExpressionTranslator(this, predef, preModifyHeap);
var updatedFrameEtran = new ExpressionTranslator(etran, modifyFrameName);
- builder.Add(new Bpl.AssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));
+ builder.Add(TrAssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));
} else {
// do the body, but with preModifyHeapVar as the governing frame
var updatedFrameEtran = new ExpressionTranslator(etran, modifyFrameName);
@@ -7223,6 +7531,8 @@ namespace Microsoft.Dafny {
} else if (stmt is ForallStmt) {
var s = (ForallStmt)stmt;
+ this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);
+
if (s.Kind == ForallStmt.ParBodyKind.Assign) {
AddComment(builder, stmt, "forall statement (assign)");
Contract.Assert(s.Ens.Count == 0);
@@ -7232,6 +7542,7 @@ namespace Microsoft.Dafny {
var s0 = (AssignStmt)s.S0;
var definedness = new Bpl.StmtListBuilder();
var updater = new Bpl.StmtListBuilder();
+ DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);
TrForallAssign(s, s0, definedness, updater, locals, etran);
// All done, so put the two pieces together
builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, updater.Collect(s.Tok)));
@@ -7247,8 +7558,9 @@ namespace Microsoft.Dafny {
} else {
var s0 = (CallStmt)s.S0;
var definedness = new Bpl.StmtListBuilder();
+ DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);
var exporter = new Bpl.StmtListBuilder();
- TrForallStmtCall(s.Tok, s.BoundVars, s.Range, null, s0, definedness, exporter, locals, etran);
+ TrForallStmtCall(s.Tok, s.BoundVars, s.Range, null, s.ForallExpressions, s0, definedness, exporter, locals, etran);
// All done, so put the two pieces together
builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, exporter.Collect(s.Tok)));
builder.Add(CaptureState(stmt));
@@ -7258,6 +7570,7 @@ namespace Microsoft.Dafny {
AddComment(builder, stmt, "forall statement (proof)");
var definedness = new Bpl.StmtListBuilder();
var exporter = new Bpl.StmtListBuilder();
+ DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);
TrForallProof(s, definedness, exporter, locals, etran);
// All done, so put the two pieces together
builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, exporter.Collect(s.Tok)));
@@ -7266,7 +7579,7 @@ namespace Microsoft.Dafny {
} else {
Contract.Assert(false); // unexpected kind
}
-
+ this.fuelContext = FuelSetting.PopFuelContext();
} else if (stmt is CalcStmt) {
/* Translate into:
if (*) {
@@ -7292,6 +7605,8 @@ namespace Microsoft.Dafny {
var s = (CalcStmt)stmt;
Contract.Assert(s.Steps.Count == s.Hints.Count); // established by the resolver
AddComment(builder, stmt, "calc statement");
+ this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);
+ DefineFuelConstant(stmt.Tok, stmt.Attributes, builder, etran);
CurrentIdGenerator.Push(); // put the entire calc statement within its own sub-branch
if (s.Lines.Count > 0) {
Bpl.IfCmd ifCmd = null;
@@ -7310,7 +7625,7 @@ namespace Microsoft.Dafny {
if (s.Steps[i] is BinaryExpr && (((BinaryExpr)s.Steps[i]).ResolvedOp == BinaryExpr.ResolvedOpcode.Imp)) {
// assume line<i>:
AddComment(b, stmt, "assume lhs");
- b.Add(new Bpl.AssumeCmd(s.Tok, etran.TrExpr(CalcStmt.Lhs(s.Steps[i]))));
+ b.Add(TrAssumeCmd(s.Tok, etran.TrExpr(CalcStmt.Lhs(s.Steps[i]))));
}
// hint:
AddComment(b, stmt, "Hint" + i.ToString());
@@ -7338,7 +7653,7 @@ namespace Microsoft.Dafny {
}
}
}
- b.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ b.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), ifCmd, null);
CurrentIdGenerator.Pop();
}
@@ -7347,23 +7662,23 @@ namespace Microsoft.Dafny {
AddComment(b, stmt, "assert wf[initial]");
Contract.Assert(s.Result != null); // established by the resolver
TrStmt_CheckWellformed(CalcStmt.Lhs(s.Result), b, locals, etran, false);
- b.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ b.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), ifCmd, null);
builder.Add(ifCmd);
// assume result:
if (s.Steps.Count > 1) {
- builder.Add(new Bpl.AssumeCmd(s.Tok, etran.TrExpr(s.Result)));
+ builder.Add(TrAssumeCmd(s.Tok, etran.TrExpr(s.Result)));
}
}
CurrentIdGenerator.Pop();
-
+ this.fuelContext = FuelSetting.PopFuelContext();
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
TrStmt_CheckWellformed(s.Source, builder, locals, etran, true);
Bpl.Expr source = etran.TrExpr(s.Source);
var b = new Bpl.StmtListBuilder();
- b.Add(new Bpl.AssumeCmd(stmt.Tok, Bpl.Expr.False));
+ b.Add(TrAssumeCmd(stmt.Tok, Bpl.Expr.False));
Bpl.StmtList els = b.Collect(stmt.Tok);
Bpl.IfCmd ifCmd = null;
foreach (var missingCtor in s.MissingCases) {
@@ -7432,12 +7747,57 @@ namespace Microsoft.Dafny {
if (s.Update != null) {
TrStmt(s.Update, builder, locals, etran);
}
-
+ } else if (stmt is LetStmt) {
+ var s = (LetStmt)stmt;
+ foreach (var bv in s.BoundVars) {
+ Bpl.LocalVariable bvar = new Bpl.LocalVariable(bv.Tok, new Bpl.TypedIdent(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), TrType(bv.Type)));
+ locals.Add(bvar);
+ var bIe = new Bpl.IdentifierExpr(bvar.tok, bvar);
+ builder.Add(new Bpl.HavocCmd(bv.Tok, new List<Bpl.IdentifierExpr> { bIe }));
+ Bpl.Expr wh = GetWhereClause(bv.Tok, bIe, bv.Type, etran);
+ if (wh != null) {
+ builder.Add(TrAssumeCmd(bv.Tok, wh));
+ }
+ }
+ Contract.Assert(s.LHSs.Count == s.RHSs.Count); // checked by resolution
+ var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator("let#");
+ for (int i = 0; i < s.LHSs.Count; i++) {
+ var pat = s.LHSs[i];
+ var rhs = s.RHSs[i];
+ var nm = varNameGen.FreshId(string.Format("#{0}#", i));
+ var r = new Bpl.LocalVariable(pat.tok, new Bpl.TypedIdent(pat.tok, nm, TrType(rhs.Type)));
+ locals.Add(r);
+ var rIe = new Bpl.IdentifierExpr(pat.tok, r);
+ TrStmt_CheckWellformed(s.RHSs[i], builder, locals, etran, false);
+ CheckWellformedWithResult(s.RHSs[i], new WFOptions(null, false, false), rIe, pat.Expr.Type, locals, builder, etran);
+ CheckCasePatternShape(pat, rIe, builder);
+ builder.Add(TrAssumeCmd(pat.tok, Bpl.Expr.Eq(etran.TrExpr(pat.Expr), rIe)));
+ }
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
}
}
+ private void IntroduceAndAssignExistentialVars(ExistsExpr exists, Bpl.StmtListBuilder builder, Bpl.StmtListBuilder builderOutsideIfConstruct, List<Variable> locals, ExpressionTranslator etran) {
+ Contract.Requires(exists != null);
+ Contract.Requires(exists.Range == null);
+ Contract.Requires(builder != null);
+ Contract.Requires(builderOutsideIfConstruct != null);
+ Contract.Requires(locals != null);
+ Contract.Requires(etran != null);
+ // declare and havoc the bound variables of 'exists' as local variables
+ var iesForHavoc = new List<Bpl.IdentifierExpr>();
+ foreach (var bv in exists.BoundVars) {
+ Bpl.Type varType = TrType(bv.Type);
+ Bpl.Expr wh = GetWhereClause(bv.Tok, new Bpl.IdentifierExpr(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType), bv.Type, etran);
+ Bpl.Variable local = new Bpl.LocalVariable(bv.Tok, new Bpl.TypedIdent(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh));
+ locals.Add(local);
+ iesForHavoc.Add(new Bpl.IdentifierExpr(local.tok, local));
+ }
+ builderOutsideIfConstruct.Add(new Bpl.HavocCmd(exists.tok, iesForHavoc));
+ builder.Add(TrAssumeCmd(exists.tok, etran.TrExpr(exists.Term)));
+ }
+
void TrStmtList(List<Statement> stmts, Bpl.StmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {
Contract.Requires(stmts != null);
Contract.Requires(builder != null);
@@ -7452,6 +7812,46 @@ namespace Microsoft.Dafny {
}
/// <summary>
+ /// Returns an expression like 'exists' but where the bound variables have been renamed to have
+ /// 'prefix' as a prefix to their previous names.
+ /// Assumes the expression has been resolved.
+ /// </summary>
+ public static Expression AlphaRename(ExistsExpr exists, string prefix, Translator translator) {
+ Contract.Requires(exists != null);
+ Contract.Requires(prefix != null);
+ Contract.Requires(translator != null);
+
+ if (exists.SplitQuantifier != null) {
+ // TODO: what to do? Substitute(exists.SplitQuantifierExpression);
+ }
+
+ var substMap = new Dictionary<IVariable, Expression>();
+ var var4var = new Dictionary<BoundVar, BoundVar>();
+ var bvars = new List<BoundVar>();
+ foreach (var bv in exists.BoundVars) {
+ var newBv = new BoundVar(bv.tok, prefix + bv.Name, bv.Type);
+ bvars.Add(newBv);
+ var4var.Add(bv, newBv);
+ var ie = new IdentifierExpr(newBv.tok, newBv.Name);
+ ie.Var = newBv; // resolve here
+ ie.Type = newBv.Type; // resolve here
+ substMap.Add(bv, ie);
+ }
+ var s = new Substituter(null, substMap, new Dictionary<TypeParameter, Type>(), translator);
+ var range = exists.Range == null ? null : s.Substitute(exists.Range);
+ var term = s.Substitute(exists.Term);
+ var attrs = s.SubstAttributes(exists.Attributes);
+ var ex = new ExistsExpr(exists.tok, exists.TypeArgs, bvars, range, term, attrs);
+ if (exists.Bounds != null) {
+ ex.Bounds = exists.Bounds.ConvertAll(bound => s.SubstituteBoundedPool(bound));
+ }
+ if (exists.MissingBounds != null) {
+ ex.MissingBounds = exists.MissingBounds.ConvertAll(bv => var4var[bv]);
+ }
+ return ex;
+ }
+
+ /// <summary>
/// Generate:
/// havoc Heap \ {this} \ _reads \ _new;
/// assume this.Valid();
@@ -7477,7 +7877,7 @@ namespace Microsoft.Dafny {
new List<Bpl.IdentifierExpr>()));
// assume YieldRequires;
foreach (var p in iter.YieldRequires) {
- builder.Add(new Bpl.AssumeCmd(tok, etran.TrExpr(p.E)));
+ builder.Add(TrAssumeCmd(tok, etran.TrExpr(p.E)));
}
// $_OldIterHeap := Heap;
builder.Add(Bpl.Cmd.SimpleAssign(tok, new Bpl.IdentifierExpr(tok, "$_OldIterHeap", predef.HeapType), etran.HeapExpr));
@@ -7550,7 +7950,7 @@ namespace Microsoft.Dafny {
}
}
} else if (xType is SetType) {
- var empty = new SetDisplayExpr(x.tok, new List<Expression>());
+ var empty = new SetDisplayExpr(x.tok, ((SetType)xType).Finite, new List<Expression>());
empty.Type = xType;
yield return empty;
} else if (xType is MultiSetType) {
@@ -7572,39 +7972,37 @@ namespace Microsoft.Dafny {
}
var missingBounds = new List<BoundVar>();
- var bounds = Resolver.DiscoverBounds(x.tok, new List<BoundVar>() { x }, expr, true, true, missingBounds);
- if (missingBounds.Count == 0) {
- foreach (var bound in bounds) {
- if (bound is ComprehensionExpr.IntBoundedPool) {
- var bnd = (ComprehensionExpr.IntBoundedPool)bound;
- if (bnd.LowerBound != null) yield return bnd.LowerBound;
- if (bnd.UpperBound != null) yield return Expression.CreateDecrement(bnd.UpperBound, 1);
- } else if (bound is ComprehensionExpr.SubSetBoundedPool) {
- var bnd = (ComprehensionExpr.SubSetBoundedPool)bound;
- yield return bnd.UpperBound;
- } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {
- var bnd = (ComprehensionExpr.SuperSetBoundedPool)bound;
- yield return bnd.LowerBound;
- } else if (bound is ComprehensionExpr.SetBoundedPool) {
- var st = ((ComprehensionExpr.SetBoundedPool)bound).Set.Resolved;
- if (st is DisplayExpression) {
- var display = (DisplayExpression)st;
- foreach (var el in display.Elements) {
- yield return el;
- }
- } else if (st is MapDisplayExpr) {
- var display = (MapDisplayExpr)st;
- foreach (var maplet in display.Elements) {
- yield return maplet.A;
- }
+ var bounds = Resolver.DiscoverAllBounds_SingleVar(x, expr);
+ foreach (var bound in bounds) {
+ if (bound is ComprehensionExpr.IntBoundedPool) {
+ var bnd = (ComprehensionExpr.IntBoundedPool)bound;
+ if (bnd.LowerBound != null) yield return bnd.LowerBound;
+ if (bnd.UpperBound != null) yield return Expression.CreateDecrement(bnd.UpperBound, 1);
+ } else if (bound is ComprehensionExpr.SubSetBoundedPool) {
+ var bnd = (ComprehensionExpr.SubSetBoundedPool)bound;
+ yield return bnd.UpperBound;
+ } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {
+ var bnd = (ComprehensionExpr.SuperSetBoundedPool)bound;
+ yield return bnd.LowerBound;
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var st = ((ComprehensionExpr.SetBoundedPool)bound).Set.Resolved;
+ if (st is DisplayExpression) {
+ var display = (DisplayExpression)st;
+ foreach (var el in display.Elements) {
+ yield return el;
}
- } else if (bound is ComprehensionExpr.SeqBoundedPool) {
- var sq = ((ComprehensionExpr.SeqBoundedPool)bound).Seq.Resolved;
- var display = sq as DisplayExpression;
- if (display != null) {
- foreach (var el in display.Elements) {
- yield return el;
- }
+ } else if (st is MapDisplayExpr) {
+ var display = (MapDisplayExpr)st;
+ foreach (var maplet in display.Elements) {
+ yield return maplet.A;
+ }
+ }
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var sq = ((ComprehensionExpr.SeqBoundedPool)bound).Seq.Resolved;
+ var display = sq as DisplayExpression;
+ if (display != null) {
+ foreach (var el in display.Elements) {
+ yield return el;
}
}
}
@@ -7694,7 +8092,7 @@ namespace Microsoft.Dafny {
var substMap = SetupBoundVarsAsLocals(s.BoundVars, definedness, locals, etran);
Expression range = Substitute(s.Range, null, substMap);
TrStmt_CheckWellformed(range, definedness, locals, etran, false);
- definedness.Add(new Bpl.AssumeCmd(s.Range.tok, etran.TrExpr(range)));
+ definedness.Add(TrAssumeCmd(s.Range.tok, etran.TrExpr(range)));
var lhs = Substitute(s0.Lhs.Resolved, null, substMap);
TrStmt_CheckWellformed(lhs, definedness, locals, etran, false);
@@ -7730,7 +8128,7 @@ namespace Microsoft.Dafny {
var substMapPrime = SetupBoundVarsAsLocals(s.BoundVars, definedness, locals, etran);
var lhsPrime = Substitute(s0.Lhs.Resolved, null, substMapPrime);
range = Substitute(s.Range, null, substMapPrime);
- definedness.Add(new Bpl.AssumeCmd(range.tok, etran.TrExpr(range)));
+ definedness.Add(TrAssumeCmd(range.tok, etran.TrExpr(range)));
// assume !(x == x' && y == y');
Bpl.Expr eqs = Bpl.Expr.True;
foreach (var bv in s.BoundVars) {
@@ -7739,7 +8137,7 @@ namespace Microsoft.Dafny {
// TODO: in the following line, is the term equality okay, or does it have to include things like Set#Equal sometimes too?
eqs = BplAnd(eqs, Bpl.Expr.Eq(etran.TrExpr(x), etran.TrExpr(xPrime)));
}
- definedness.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.Not(eqs)));
+ definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.Not(eqs)));
Bpl.Expr objPrime, FPrime;
GetObjFieldDetails(lhsPrime, etran, out objPrime, out FPrime);
var Rhs = ((ExprRhs)s0.Rhs).Expr;
@@ -7752,7 +8150,7 @@ namespace Microsoft.Dafny {
"left-hand sides for different forall-statement bound variables may refer to the same location"));
}
- definedness.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
// Now for the translation of the update itself
@@ -7760,7 +8158,7 @@ namespace Microsoft.Dafny {
var prevEtran = new ExpressionTranslator(this, predef, prevHeap);
updater.Add(Bpl.Cmd.SimpleAssign(s.Tok, prevHeap, etran.HeapExpr));
updater.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));
- updater.Add(new Bpl.AssumeCmd(s.Tok, FunctionCall(s.Tok, BuiltinFunction.HeapSucc, null, prevHeap, etran.HeapExpr)));
+ updater.Add(TrAssumeCmd(s.Tok, HeapSucc(prevHeap, etran.HeapExpr)));
// Here comes:
// assume (forall<alpha> o: ref, f: Field alpha ::
@@ -7782,71 +8180,23 @@ namespace Microsoft.Dafny {
GetObjFieldDetails(s0.Lhs.Resolved, prevEtran, out xObj, out xField);
xBody = BplAnd(xBody, Bpl.Expr.Eq(o, xObj));
xBody = BplAnd(xBody, Bpl.Expr.Eq(f, xField));
- Bpl.Expr xObjField = new Bpl.ExistsExpr(s.Tok, xBvars, xBody);
+ //TRIG (exists k#2: int :: (k#2 == LitInt(0 - 3) || k#2 == LitInt(4)) && $o == read($prevHeap, this, _module.MyClass.arr) && $f == MultiIndexField(IndexField(i#0), j#0))
+ Bpl.Expr xObjField = new Bpl.ExistsExpr(s.Tok, xBvars, xBody); // LL_TRIGGER
Bpl.Expr body = Bpl.Expr.Or(Bpl.Expr.Eq(heapOF, oldHeapOF), xObjField);
var tr = new Trigger(s.Tok, true, new List<Expr>() { heapOF });
Bpl.Expr qq = new Bpl.ForallExpr(s.Tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null, tr, body);
- updater.Add(new Bpl.AssumeCmd(s.Tok, qq));
+ updater.Add(TrAssumeCmd(s.Tok, qq));
- if (s0.Rhs is ExprRhs) {
- Expression Fi = null;
- Func<Expression,Expression> lhsBuilder = null;
- lhs = s0.Lhs.Resolved;
- var i = s.BoundVars[0];
- if (s.BoundVars.Count == 1) {
- //var lhsContext = null;
- // Detect the following cases:
- // 0: forall i | R(i) { F(i).f := E(i); }
- // 1: forall i | R(i) { A[F(i)] := E(i); }
- // 2: forall i | R(i) { F(i)[N] := E(i); }
- if (lhs is MemberSelectExpr) {
- var ll = (MemberSelectExpr)lhs;
- Fi = ll.Obj;
- lhsBuilder = e => { var l = new MemberSelectExpr(ll.tok, e, ll.MemberName); l.Member = ll.Member; l.Type = ll.Type; return l; };
- } else if (lhs is SeqSelectExpr) {
- var ll = (SeqSelectExpr)lhs;
- Contract.Assert(ll.SelectOne);
- if (!ContainsFreeVariable(ll.Seq, false, i)) {
- Fi = ll.E0;
- lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, ll.Seq, e, null); l.Type = ll.Type; return l; };
- } else if (!ContainsFreeVariable(ll.E0, false, i)) {
- Fi = ll.Seq;
- lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, e, ll.E0, null); l.Type = ll.Type; return l; };
- }
- }
- }
- var rhs = ((ExprRhs)s0.Rhs).Expr;
- bool usedInversion = false;
- if (Fi != null) {
- var j = new BoundVar(i.tok, i.Name + "#inv", Fi.Type);
- var jj = Expression.CreateIdentExpr(j);
- var jList = new List<BoundVar>() { j };
- var vals = InvertExpression(i, j, s.Range, Fi);
-#if DEBUG_PRINT
- Console.WriteLine("DEBUG: Trying to invert:");
- Console.WriteLine("DEBUG: " + Printer.ExprToString(s.Range) + " && " + j.Name + " == " + Printer.ExprToString(Fi));
- if (vals == null) {
- Console.WriteLine("DEBUG: Can't");
- } else {
- Console.WriteLine("DEBUG: The inverse is the disjunction of the following:");
- foreach (var val in vals) {
- Console.WriteLine("DEBUG: " + Printer.ExprToString(val.Range) + " && " + Printer.ExprToString(val.FInverse) + " == " + i.Name);
- }
- }
-#endif
- if (vals != null) {
- foreach (var val in vals) {
- qq = TrForall_NewValueAssumption(s.Tok, jList, val.Range, lhsBuilder(jj), Substitute(rhs, i, val.FInverse), true, etran, prevEtran);
- updater.Add(new Bpl.AssumeCmd(s.Tok, qq));
- }
- usedInversion = true;
- }
- }
- if (!usedInversion) {
- qq = TrForall_NewValueAssumption(s.Tok, s.BoundVars, s.Range, lhs, rhs, false, etran, prevEtran);
- updater.Add(new Bpl.AssumeCmd(s.Tok, qq));
+ if (s.ForallExpressions != null) {
+ foreach (ForallExpr expr in s.ForallExpressions) {
+ BinaryExpr term = (BinaryExpr)expr.Term;
+ Contract.Assert(term != null);
+ var e0 = Substitute(((BinaryExpr)term).E0.Resolved, null, substMap);
+ var e1 = Substitute(((BinaryExpr)term).E1, null, substMap);
+ qq = TrForall_NewValueAssumption(expr.tok, expr.BoundVars, expr.Range, e0, e1, expr.Attributes, etran, prevEtran);
+ updater.Add(TrAssumeCmd(s.Tok, qq));
}
- }
+ }
}
/// <summary>
@@ -7860,7 +8210,7 @@ namespace Microsoft.Dafny {
/// G is rhs
/// If lhsAsTrigger is true, then use the LHS of the equality above as the trigger; otherwise, don't specify any trigger.
/// </summary>
- private Bpl.Expr TrForall_NewValueAssumption(IToken tok, List<BoundVar> boundVars, Expression range, Expression lhs, Expression rhs, bool lhsAsTrigger, ExpressionTranslator etran, ExpressionTranslator prevEtran) {
+ private Bpl.Expr TrForall_NewValueAssumption(IToken tok, List<BoundVar> boundVars, Expression range, Expression lhs, Expression rhs, Attributes attributes, ExpressionTranslator etran, ExpressionTranslator prevEtran) {
Contract.Requires(tok != null);
Contract.Requires(boundVars != null);
Contract.Requires(range != null);
@@ -7880,159 +8230,27 @@ namespace Microsoft.Dafny {
Type lhsType = lhs is MemberSelectExpr ? ((MemberSelectExpr)lhs).Type : null;
g = CondApplyBox(rhs.tok, g, rhs.Type, lhsType);
- Trigger tr = lhsAsTrigger ? new Trigger(tok, true, new List<Bpl.Expr>() { xHeapOF }) : null;
- return new Bpl.ForallExpr(tok, xBvars, tr, Bpl.Expr.Imp(xAnte, Bpl.Expr.Eq(xHeapOF, g)));
- }
-
- class ForallStmtTranslationValues
- {
- public readonly Expression Range;
- public readonly Expression FInverse;
- public ForallStmtTranslationValues(Expression range, Expression fInverse) {
- Contract.Requires(range != null);
- Contract.Requires(fInverse != null);
- Range = range;
- FInverse = fInverse;
- }
- public ForallStmtTranslationValues Subst(IVariable j, Expression e, Translator translator) {
- Contract.Requires(j != null);
- Contract.Requires(e != null);
- Contract.Requires(translator != null);
- var substMap = new Dictionary<IVariable, Expression>();
- substMap.Add(j, e);
- var v = new ForallStmtTranslationValues(translator.Substitute(Range, null, substMap), translator.Substitute(FInverse, null, substMap));
- return v;
- }
- }
-
- /// <summary>
- /// Find piecewise inverse of F under R. More precisely, find lists of expressions P and F-1
- /// such that
- /// R(i) && j == F(i)
- /// holds iff the disjunction of the following predicates holds:
- /// P_0(j) && F-1_0(j) == i
- /// ...
- /// P_{n-1}(j) && F-1_{n-1}(j) == i
- /// If no such disjunction is found, return null.
- /// If such a disjunction is found, return for each disjunct:
- /// * The predicate P_k(j), which is an expression that may have free occurrences of j (but no free occurrences of i)
- /// * The expression F-1_k(j), which also may have free occurrences of j but not of i
- /// </summary>
- private List<ForallStmtTranslationValues> InvertExpression(BoundVar i, BoundVar j, Expression R, Expression F) {
- Contract.Requires(i != null);
- Contract.Requires(j != null);
- Contract.Requires(R != null);
- Contract.Requires(F != null);
- var vals = new List<ForallStmtTranslationValues>(InvertExpressionIter(i, j, R, F));
- if (vals.Count == 0) {
- return null;
- } else {
- return vals;
- }
- }
- /// <summary>
- /// See InvertExpression.
- /// </summary>
- private IEnumerable<ForallStmtTranslationValues> InvertExpressionIter(BoundVar i, BoundVar j, Expression R, Expression F) {
- Contract.Requires(i != null);
- Contract.Requires(j != null);
- Contract.Requires(R != null);
- Contract.Requires(F != null);
- F = F.Resolved;
- if (!ContainsFreeVariable(F, false, i)) {
- // We're looking at R(i) && j == K.
- // We cannot invert j == K, but if we're lucky, R(i) contains a conjunct i==G.
- Expression r = Expression.CreateBoolLiteral(R.tok, true);
- Expression G = null;
- foreach (var c in Expression.Conjuncts(R)) {
- if (G == null && c is BinaryExpr) {
- var bin = (BinaryExpr)c;
- if (BinaryExpr.IsEqualityOp(bin.ResolvedOp)) {
- var id = bin.E0.Resolved as IdentifierExpr;
- if (id != null && id.Var == i) {
- G = bin.E1;
- continue;
- }
- id = bin.E1.Resolved as IdentifierExpr;
- if (id != null && id.Var == i) {
- G = bin.E0;
- continue;
- }
+ Bpl.Trigger tr = null;
+ var argsEtran = etran.WithNoLits();
+ foreach (var aa in attributes.AsEnumerable()) {
+ if (aa.Name == "trigger") {
+ List<Bpl.Expr> tt = new List<Bpl.Expr>();
+ foreach (var arg in aa.Args) {
+ if (arg == lhs) {
+ tt.Add(xHeapOF);
+ } else {
+ tt.Add(argsEtran.TrExpr(arg));
}
}
- r = Expression.CreateAnd(r, c);
- }
- if (G != null) {
- var jIsK = Expression.CreateEq(Expression.CreateIdentExpr(j), F, j.Type);
- var rr = Substitute(r, i, G);
- yield return new ForallStmtTranslationValues(Expression.CreateAnd(rr, jIsK), G);
- }
- } else if (F is IdentifierExpr) {
- var e = (IdentifierExpr)F;
- if (e.Var == i) {
- // We're looking at R(i) && j == i, which is particularly easy to invert: R(j) && j == i
- var jj = Expression.CreateIdentExpr(j);
- yield return new ForallStmtTranslationValues(Substitute(R, i, jj), jj);
- }
- } else if (F is BinaryExpr) {
- var bin = (BinaryExpr)F;
- if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {
- if (!ContainsFreeVariable(bin.E1, false, i)) {
- // We're looking at: R(i) && j == f(i) + K.
- // By a recursive call, we'll ask to invert: R(i) && j' == f(i).
- // For each P_0(j') && f-1_0(j') == i we get back, we yield:
- // P_0(j - K) && f-1_0(j - K) == i
- var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E1);
- foreach (var val in InvertExpression(i, j, R, bin.E0)) {
- yield return val.Subst(j, jMinusK, this);
- }
- } else if (!ContainsFreeVariable(bin.E0, false, i)) {
- // We're looking at: R(i) && j == K + f(i)
- // Do as in previous case, but with operands reversed.
- var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E0);
- foreach (var val in InvertExpression(i, j, R, bin.E1)) {
- yield return val.Subst(j, jMinusK, this);
- }
- }
- } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {
- if (!ContainsFreeVariable(bin.E1, false, i)) {
- // We're looking at: R(i) && j == f(i) - K
- // Recurse on f(i) and then replace j := j + K
- var jPlusK = Expression.CreateAdd(Expression.CreateIdentExpr(j), bin.E1);
- foreach (var val in InvertExpression(i, j, R, bin.E0)) {
- yield return val.Subst(j, jPlusK, this);
- }
- } else if (!ContainsFreeVariable(bin.E0, false, i)) {
- // We're looking at: R(i) && j == K - f(i)
- // Recurse on f(i) and then replace j := K - j
- var kMinusJ = Expression.CreateAdd(Expression.CreateIdentExpr(j), bin.E0);
- foreach (var val in InvertExpression(i, j, R, bin.E1)) {
- yield return val.Subst(j, kMinusJ, this);
- }
- }
- }
- } else if (F is ITEExpr) {
- var ife = (ITEExpr)F;
- // We're looking at R(i) && j == if A(i) then B(i) else C(i), which is equivalent to the disjunction of:
- // R(i) && A(i) && j == B(i)
- // R(i) && !A(i) && j == C(i)
- // We recurse on each one, yielding the results
- var r = Expression.CreateAnd(R, ife.Test);
- var valsThen = InvertExpression(i, j, r, ife.Thn);
- if (valsThen != null) {
- r = Expression.CreateAnd(R, Expression.CreateNot(ife.tok, ife.Test));
- var valsElse = InvertExpression(i, j, r, ife.Els);
- if (valsElse != null) {
- foreach (var val in valsThen) { yield return val; }
- foreach (var val in valsElse) { yield return val; }
- }
+ tr = new Bpl.Trigger(tok, true, tt, tr);
}
}
+ return new Bpl.ForallExpr(tok, xBvars, tr, Bpl.Expr.Imp(xAnte, Bpl.Expr.Eq(xHeapOF, g)));
}
delegate Bpl.Expr ExpressionConverter(Dictionary<IVariable, Expression> substMap, ExpressionTranslator etran);
- void TrForallStmtCall(IToken tok, List<BoundVar> boundVars, Expression range, ExpressionConverter additionalRange, CallStmt s0,
+ void TrForallStmtCall(IToken tok, List<BoundVar> boundVars, Expression range, ExpressionConverter additionalRange, List<Expression> forallExpressions, CallStmt s0,
Bpl.StmtListBuilder definedness, Bpl.StmtListBuilder exporter, List<Variable> locals, ExpressionTranslator etran) {
Contract.Requires(tok != null);
Contract.Requires(boundVars != null);
@@ -8079,18 +8297,18 @@ namespace Microsoft.Dafny {
havocIds.Add(new Bpl.IdentifierExpr(tok, bv));
}
definedness.Add(new Bpl.HavocCmd(tok, havocIds));
- definedness.Add(new Bpl.AssumeCmd(tok, ante));
+ definedness.Add(TrAssumeCmd(tok, ante));
}
TrStmt_CheckWellformed(range, definedness, locals, etran, false);
- definedness.Add(new Bpl.AssumeCmd(range.tok, etran.TrExpr(range)));
+ definedness.Add(TrAssumeCmd(range.tok, etran.TrExpr(range)));
if (additionalRange != null) {
var es = additionalRange(new Dictionary<IVariable, Expression>(), etran);
- definedness.Add(new Bpl.AssumeCmd(es.tok, es));
+ definedness.Add(TrAssumeCmd(es.tok, es));
}
TrStmt(s0, definedness, locals, etran);
- definedness.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.False));
+ definedness.Add(TrAssumeCmd(tok, Bpl.Expr.False));
}
// Now for the other branch, where the postcondition of the call is exported.
@@ -8107,7 +8325,7 @@ namespace Microsoft.Dafny {
Contract.Assert(s0.Method.Mod.Expressions.Count == 0); // checked by the resolver
foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(tok, new List<FrameExpression>(), s0.IsGhost, initEtran, etran, initEtran)) {
if (tri.IsFree) {
- exporter.Add(new Bpl.AssumeCmd(tok, tri.Expr));
+ exporter.Add(TrAssumeCmd(tok, tri.Expr));
}
}
if (codeContext is IteratorDecl) {
@@ -8115,35 +8333,56 @@ namespace Microsoft.Dafny {
RecordNewObjectsIn_New(tok, iter, initHeap, heapIdExpr, exporter, locals, etran);
}
- var bvars = new List<Variable>();
- Dictionary<IVariable, Expression> substMap;
- var ante = initEtran.TrBoundVariablesRename(boundVars, bvars, out substMap);
- ante = BplAnd(ante, initEtran.TrExpr(Substitute(range, null, substMap)));
- if (additionalRange != null) {
- ante = BplAnd(ante, additionalRange(substMap, initEtran));
- }
-
- // Note, in the following, we need to do a bit of a song and dance. The actual arguements of the
+ // Note, in the following, we need to do a bit of a song and dance. The actual arguments of the
// call should be translated using "initEtran", whereas the method postcondition should be translated
// using "callEtran". To accomplish this, we translate the argument and then tuck the resulting
// Boogie expressions into BoogieExprWrappers that are used in the DafnyExpr-to-DafnyExpr substitution.
- // TODO
- var argsSubstMap = new Dictionary<IVariable, Expression>(); // maps formal arguments to actuals
- Contract.Assert(s0.Method.Ins.Count == s0.Args.Count);
- for (int i = 0; i < s0.Method.Ins.Count; i++) {
- var arg = Substitute(s0.Args[i], null, substMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the renamed bound variables for the declared ones
- argsSubstMap.Add(s0.Method.Ins[i], new BoogieWrapper(initEtran.TrExpr(arg), s0.Args[i].Type));
- }
- var receiver = new BoogieWrapper(initEtran.TrExpr(Substitute(s0.Receiver, null, substMap, s0.MethodSelect.TypeArgumentSubstitutions())), s0.Receiver.Type);
- var callEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, initHeap);
- Bpl.Expr post = Bpl.Expr.True;
- foreach (var ens in s0.Method.Ens) {
- var p = Substitute(ens.E, receiver, argsSubstMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the call's actuals for the method's formals
- post = BplAnd(post, callEtran.TrExpr(p));
- }
-
- Bpl.Expr qq = new Bpl.ForallExpr(tok, bvars, Bpl.Expr.Imp(ante, post));
- exporter.Add(new Bpl.AssumeCmd(tok, qq));
+ // TODO
+ Bpl.Expr qq;
+ if (forallExpressions != null) {
+ var callEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, initHeap);
+ foreach (Expression expr in forallExpressions) {
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ var e = Substitute(expr, null, substMap, null);
+ var argsSubstMap = new Dictionary<IVariable, Expression>();
+ Contract.Assert(s0.Method.Ins.Count == s0.Args.Count);
+ for (int i = 0; i < s0.Method.Ins.Count; i++) {
+ var arg = Substitute(s0.Args[i], null, substMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the renamed bound variables for the declared ones
+ argsSubstMap.Add(s0.Method.Ins[i], new BoogieWrapper(initEtran.TrExpr(arg), s0.Args[i].Type));
+ }
+ var receiver = new BoogieWrapper(initEtran.TrExpr(Substitute(s0.Receiver, null, substMap, s0.MethodSelect.TypeArgumentSubstitutions())), s0.Receiver.Type);
+ var p = Substitute(e, receiver, argsSubstMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the call's actuals for the method's formals
+ qq = callEtran.TrExpr(p, initEtran, null, null);
+ exporter.Add(TrAssumeCmd(tok, qq));
+ }
+ } else {
+ var bvars = new List<Variable>();
+ Dictionary<IVariable, Expression> substMap;
+ var ante = initEtran.TrBoundVariablesRename(boundVars, bvars, out substMap);
+ var argsSubstMap = new Dictionary<IVariable, Expression>(); // maps formal arguments to actuals
+ Contract.Assert(s0.Method.Ins.Count == s0.Args.Count);
+ for (int i = 0; i < s0.Method.Ins.Count; i++) {
+ var arg = Substitute(s0.Args[i], null, substMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the renamed bound variables for the declared ones
+ argsSubstMap.Add(s0.Method.Ins[i], new BoogieWrapper(initEtran.TrExpr(arg), s0.Args[i].Type));
+ }
+ var callEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, initHeap);
+ ante = BplAnd(ante, initEtran.TrExpr(Substitute(range, null, substMap)));
+ if (additionalRange != null) {
+ ante = BplAnd(ante, additionalRange(substMap, initEtran));
+ }
+ var receiver = new BoogieWrapper(initEtran.TrExpr(Substitute(s0.Receiver, null, substMap, s0.MethodSelect.TypeArgumentSubstitutions())), s0.Receiver.Type);
+ Bpl.Expr post = Bpl.Expr.True;
+ foreach (var ens in s0.Method.Ens) {
+ var p = Substitute(ens.E, receiver, argsSubstMap, s0.MethodSelect.TypeArgumentSubstitutions()); // substitute the call's actuals for the method's formals
+ post = BplAnd(post, callEtran.TrExpr(p));
+ }
+
+ // TRIG (forall $ih#s0#0: Seq Box :: $Is($ih#s0#0, TSeq(TChar)) && $IsAlloc($ih#s0#0, TSeq(TChar), $initHeapForallStmt#0) && Seq#Length($ih#s0#0) != 0 && Seq#Rank($ih#s0#0) < Seq#Rank(s#0) ==> (forall i#2: int :: true ==> LitInt(0) <= i#2 && i#2 < Seq#Length($ih#s0#0) ==> char#ToInt(_module.CharChar.MinChar($LS($LZ), $Heap, this, $ih#s0#0)) <= char#ToInt($Unbox(Seq#Index($ih#s0#0, i#2)): char)))
+ // TRIG (forall $ih#pat0#0: Seq Box, $ih#a0#0: Seq Box :: $Is($ih#pat0#0, TSeq(_module._default.Same0$T)) && $IsAlloc($ih#pat0#0, TSeq(_module._default.Same0$T), $initHeapForallStmt#0) && $Is($ih#a0#0, TSeq(_module._default.Same0$T)) && $IsAlloc($ih#a0#0, TSeq(_module._default.Same0$T), $initHeapForallStmt#0) && Seq#Length($ih#pat0#0) <= Seq#Length($ih#a0#0) && Seq#SameUntil($ih#pat0#0, $ih#a0#0, Seq#Length($ih#pat0#0)) && (Seq#Rank($ih#pat0#0) < Seq#Rank(pat#0) || (Seq#Rank($ih#pat0#0) == Seq#Rank(pat#0) && Seq#Rank($ih#a0#0) < Seq#Rank(a#0))) ==> _module.__default.IsRelaxedPrefixAux(_module._default.Same0$T, $LS($LZ), $Heap, $ih#pat0#0, $ih#a0#0, LitInt(1)))'
+ // TRIG (forall $ih#m0#0: DatatypeType, $ih#n0#0: DatatypeType :: $Is($ih#m0#0, Tclass._module.Nat()) && $IsAlloc($ih#m0#0, Tclass._module.Nat(), $initHeapForallStmt#0) && $Is($ih#n0#0, Tclass._module.Nat()) && $IsAlloc($ih#n0#0, Tclass._module.Nat(), $initHeapForallStmt#0) && Lit(true) && (DtRank($ih#m0#0) < DtRank(m#0) || (DtRank($ih#m0#0) == DtRank(m#0) && DtRank($ih#n0#0) < DtRank(n#0))) ==> _module.__default.mult($LS($LZ), $Heap, $ih#m0#0, _module.__default.plus($LS($LZ), $Heap, $ih#n0#0, $ih#n0#0)) == _module.__default.mult($LS($LZ), $Heap, _module.__default.plus($LS($LZ), $Heap, $ih#m0#0, $ih#m0#0), $ih#n0#0))
+ qq = new Bpl.ForallExpr(tok, bvars, Bpl.Expr.Imp(ante, post)); // SMART_TRIGGER
+ exporter.Add(TrAssumeCmd(tok, qq));
+ }
}
}
@@ -8157,7 +8396,7 @@ namespace Microsoft.Dafny {
Contract.Requires(locals != null);
Contract.Requires(etran != null);
// Add all newly allocated objects to the set this._new
- var updatedSet = new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, CurrentIdGenerator.FreshId("$iter_newUpdate"), predef.SetType(iter.tok, predef.BoxType)));
+ var updatedSet = new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, CurrentIdGenerator.FreshId("$iter_newUpdate"), predef.SetType(iter.tok, true, predef.BoxType)));
locals.Add(updatedSet);
var updatedSetIE = new Bpl.IdentifierExpr(iter.tok, updatedSet);
// call $iter_newUpdate := $IterCollectNewObjects(initHeap, $Heap, this, _new);
@@ -8209,10 +8448,10 @@ namespace Microsoft.Dafny {
havocIds.Add(new Bpl.IdentifierExpr(s.Tok, bv));
}
definedness.Add(new Bpl.HavocCmd(s.Tok, havocIds));
- definedness.Add(new Bpl.AssumeCmd(s.Tok, typeAntecedent));
+ definedness.Add(TrAssumeCmd(s.Tok, typeAntecedent));
}
TrStmt_CheckWellformed(s.Range, definedness, locals, etran, false);
- definedness.Add(new Bpl.AssumeCmd(s.Range.tok, etran.TrExpr(s.Range)));
+ definedness.Add(TrAssumeCmd(s.Range.tok, etran.TrExpr(s.Range)));
if (s.Body != null) {
TrStmt(s.Body, definedness, locals, etran);
@@ -8230,7 +8469,7 @@ namespace Microsoft.Dafny {
}
}
- definedness.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
// Now for the other branch, where the ensures clauses are exported.
@@ -8244,28 +8483,18 @@ namespace Microsoft.Dafny {
exporter.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr, etran.Tick() }));
foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(s.Tok, new List<FrameExpression>(), s.IsGhost, initEtran, etran, initEtran)) {
if (tri.IsFree) {
- exporter.Add(new Bpl.AssumeCmd(s.Tok, tri.Expr));
+ exporter.Add(TrAssumeCmd(s.Tok, tri.Expr));
}
}
- var bvars = new List<Variable>();
- Dictionary<IVariable, Expression> substMap;
- var ante = initEtran.TrBoundVariablesRename(s.BoundVars, bvars, out substMap);
- var range = Substitute(s.Range, null, substMap);
- ante = BplAnd(ante, initEtran.TrExpr(range));
-
- Bpl.Expr post = Bpl.Expr.True;
- foreach (var ens in s.Ens) {
- var p = Substitute(ens.E, null, substMap);
- post = BplAnd(post, etran.TrExpr(p));
- }
-
- Bpl.Expr qq = Bpl.Expr.Imp(ante, post);
- if (bvars.Count != 0) {
- var triggers = TrTrigger(etran, s.Attributes, s.Tok, substMap);
- qq = new Bpl.ForallExpr(s.Tok, bvars, triggers, qq);
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ var p = Substitute(s.ForallExpressions[0], null, substMap);
+ Bpl.Expr qq = etran.TrExpr(p, initEtran, null, null);
+ if (s.BoundVars.Count != 0) {
+ exporter.Add(TrAssumeCmd(s.Tok, qq));
+ } else {
+ exporter.Add(TrAssumeCmd(s.Tok, ((Bpl.ForallExpr)qq).Body));
}
- exporter.Add(new Bpl.AssumeCmd(s.Tok, qq));
}
private string GetObjFieldDetails(Expression lhs, ExpressionTranslator etran, out Bpl.Expr obj, out Bpl.Expr F) {
@@ -8289,6 +8518,15 @@ namespace Microsoft.Dafny {
return description;
}
+ Bpl.AssumeCmd TrAssumeCmd(IToken tok, Bpl.Expr expr, Bpl.QKeyValue attributes = null) {
+ var lit = RemoveLit(expr);
+ return attributes == null ? new Bpl.AssumeCmd(tok, lit) : new Bpl.AssumeCmd(tok, lit, attributes);
+ }
+
+ Bpl.AssertCmd TrAssertCmd(IToken tok, Bpl.Expr expr, Bpl.QKeyValue attributes = null) {
+ var lit = RemoveLit(expr);
+ return attributes == null ? new Bpl.AssertCmd(tok, lit) : new Bpl.AssertCmd(tok, lit, attributes);
+ }
delegate void BodyTranslator(Bpl.StmtListBuilder builder, ExpressionTranslator etran);
@@ -8337,11 +8575,11 @@ namespace Microsoft.Dafny {
Bpl.StmtListBuilder invDefinednessBuilder = new Bpl.StmtListBuilder();
foreach (MaybeFreeExpression loopInv in s.Invariants) {
TrStmt_CheckWellformed(loopInv.E, invDefinednessBuilder, locals, etran, false);
- invDefinednessBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, etran.TrExpr(loopInv.E)));
+ invDefinednessBuilder.Add(TrAssumeCmd(loopInv.E.tok, etran.TrExpr(loopInv.E)));
- invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, CanCallAssumption(loopInv.E, etran))));
+ invariants.Add(TrAssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, CanCallAssumption(loopInv.E, etran))));
if (loopInv.IsFree && !DafnyOptions.O.DisallowSoundnessCheating) {
- invariants.Add(new Bpl.AssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E))));
+ invariants.Add(TrAssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E))));
} else {
bool splitHappened;
var ss = TrSplitExpr(loopInv.E, etran, false, out splitHappened);
@@ -8354,7 +8592,7 @@ namespace Microsoft.Dafny {
if (split.IsChecked) {
invariants.Add(Assert(split.E.tok, wInv, "loop invariant violation")); // TODO: it would be fine to have this use {:subsumption 0}
} else {
- invariants.Add(new Bpl.AssumeCmd(split.E.tok, wInv));
+ invariants.Add(TrAssumeCmd(split.E.tok, wInv));
}
}
}
@@ -8370,14 +8608,14 @@ namespace Microsoft.Dafny {
// include boilerplate invariants
foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(s.Tok, modifiesClause, s.IsGhost, etranPreLoop, etran, etran.Old)) {
if (tri.IsFree) {
- invariants.Add(new Bpl.AssumeCmd(s.Tok, tri.Expr));
+ invariants.Add(TrAssumeCmd(s.Tok, tri.Expr));
} else {
Contract.Assert(tri.ErrorMessage != null); // follows from BoilerplateTriple invariant
invariants.Add(Assert(s.Tok, tri.Expr, tri.ErrorMessage));
}
}
// add a free invariant which says that the heap hasn't changed outside of the modifies clause.
- invariants.Add(new Bpl.AssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));
+ invariants.Add(TrAssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));
}
// include a free invariant that says that all completed iterations so far have only decreased the termination metric
@@ -8391,13 +8629,13 @@ namespace Microsoft.Dafny {
decrs.Add(etran.TrExpr(e));
}
Bpl.Expr decrCheck = DecreasesCheck(toks, types, types, decrs, initDecr, null, null, true, false);
- invariants.Add(new Bpl.AssumeCmd(s.Tok, decrCheck));
+ invariants.Add(TrAssumeCmd(s.Tok, decrCheck));
}
Bpl.StmtListBuilder loopBodyBuilder = new Bpl.StmtListBuilder();
loopBodyBuilder.Add(CaptureState(s.Tok, true, "after some loop iterations"));
// as the first thing inside the loop, generate: if (!w) { CheckWellformed(inv); assume false; }
- invDefinednessBuilder.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ invDefinednessBuilder.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, Bpl.Expr.Not(w), invDefinednessBuilder.Collect(s.Tok), null, null));
// generate: CheckWellformed(guard); if (!guard) { break; }
Bpl.Expr guard = null;
@@ -8438,13 +8676,13 @@ namespace Microsoft.Dafny {
loopBodyBuilder.Add(Assert(s.Tok, decrCheck, msg));
}
} else {
- loopBodyBuilder.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ loopBodyBuilder.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));
// todo(maria): havoc stuff
}
// Finally, assume the well-formedness of the invariant (which has been checked once and for all above), so that the check
// of invariant-maintenance can use the appropriate canCall predicates.
foreach (MaybeFreeExpression loopInv in s.Invariants) {
- loopBodyBuilder.Add(new Bpl.AssumeCmd(loopInv.E.tok, CanCallAssumption(loopInv.E, etran)));
+ loopBodyBuilder.Add(TrAssumeCmd(loopInv.E.tok, CanCallAssumption(loopInv.E, etran)));
}
Bpl.StmtList body = loopBodyBuilder.Collect(s.Tok);
@@ -8454,7 +8692,7 @@ namespace Microsoft.Dafny {
void TrAlternatives(List<GuardedAlternative> alternatives, Bpl.Cmd elseCase0, Bpl.StructuredCmd elseCase1,
Bpl.StmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {
Contract.Requires(alternatives != null);
- Contract.Requires((elseCase0 != null) == (elseCase1 == null)); // ugly way of doing a type union
+ Contract.Requires((elseCase0 == null) != (elseCase1 == null)); // ugly way of doing a type union
Contract.Requires(builder != null);
Contract.Requires(locals != null);
Contract.Requires(etran != null);
@@ -8468,15 +8706,18 @@ namespace Microsoft.Dafny {
return;
}
+ // alpha-rename any existential guards
+ var guards = alternatives.ConvertAll(alt => alt.IsExistentialGuard ? AlphaRename((ExistsExpr)alt.Guard, "eg$", this) : alt.Guard);
+
// build the negation of the disjunction of all guards (that is, the conjunction of their negations)
Bpl.Expr noGuard = Bpl.Expr.True;
- foreach (var alternative in alternatives) {
- noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(alternative.Guard)));
+ foreach (var g in guards) {
+ noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(g)));
}
var b = new Bpl.StmtListBuilder();
var elseTok = elseCase0 != null ? elseCase0.tok : elseCase1.tok;
- b.Add(new Bpl.AssumeCmd(elseTok, noGuard));
+ b.Add(TrAssumeCmd(elseTok, noGuard));
if (elseCase0 != null) {
b.Add(elseCase0);
} else {
@@ -8490,8 +8731,13 @@ namespace Microsoft.Dafny {
CurrentIdGenerator.Push();
var alternative = alternatives[i];
b = new Bpl.StmtListBuilder();
- TrStmt_CheckWellformed(alternative.Guard, b, locals, etran, true);
- b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard)));
+ TrStmt_CheckWellformed(guards[i], b, locals, etran, true);
+ if (alternative.IsExistentialGuard) {
+ var exists = (ExistsExpr)alternative.Guard; // the original (that is, not alpha-renamed) guard
+ IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran);
+ } else {
+ b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard)));
+ }
foreach (var s in alternative.Body) {
TrStmt(s, b, locals, etran);
}
@@ -8693,7 +8939,7 @@ namespace Microsoft.Dafny {
Contract.Assert(codeContext != null);
List<Expression> contextDecreases = codeContext.Decreases.Expressions;
List<Expression> calleeDecreases = callee.Decreases.Expressions;
- CheckCallTermination(tok, contextDecreases, calleeDecreases, null, receiver, substMap, etran, etran.Old, builder, codeContext.InferredDecreases, null);
+ CheckCallTermination(tok, contextDecreases, calleeDecreases, null, receiver, substMap, tySubst, etran, etran.Old, builder, codeContext.InferredDecreases, null);
}
// Create variables to hold the output parameters of the call, so that appropriate unboxes can be introduced.
@@ -8716,7 +8962,7 @@ namespace Microsoft.Dafny {
builder.Add(new CommentCmd("ProcessCallStmt: Make the call"));
// Make the call
- Bpl.CallCmd call = new Bpl.CallCmd(tok, MethodName(callee, kind), ins, outs);
+ Bpl.CallCmd call = Call(tok, MethodName(callee, kind), ins, outs);
if (module != currentModule && RefinementToken.IsInherited(tok, currentModule) && (codeContext == null || !codeContext.MustReverify)) {
// The call statement is inherited, so the refined module already checked that the precondition holds. Note,
// preconditions are not allowed to be strengthened, except if they use a predicate whose body has been strengthened.
@@ -8740,7 +8986,7 @@ namespace Microsoft.Dafny {
// the out-parameter.
Bpl.Cmd cmd = new Bpl.HavocCmd(bLhs.tok, new List<Bpl.IdentifierExpr> { bLhs });
builder.Add(cmd);
- cmd = new Bpl.AssumeCmd(bLhs.tok, Bpl.Expr.Eq(bLhs, FunctionCall(bLhs.tok, BuiltinFunction.Unbox, TrType(LhsTypes[i]), tmpVarIdE)));
+ cmd = TrAssumeCmd(bLhs.tok, Bpl.Expr.Eq(bLhs, FunctionCall(bLhs.tok, BuiltinFunction.Unbox, TrType(LhsTypes[i]), tmpVarIdE)));
builder.Add(cmd);
}
}
@@ -8768,7 +9014,7 @@ namespace Microsoft.Dafny {
builder.Add(new Bpl.HavocCmd(bv.tok, new List<Bpl.IdentifierExpr> { bIe }));
Bpl.Expr wh = GetWhereClause(bv.tok, bIe, local.Type, etran);
if (wh != null) {
- builder.Add(new Bpl.AssumeCmd(bv.tok, wh));
+ builder.Add(TrAssumeCmd(bv.tok, wh));
}
}
return substMap;
@@ -8804,6 +9050,7 @@ namespace Microsoft.Dafny {
void CheckCallTermination(IToken tok, List<Expression> contextDecreases, List<Expression> calleeDecreases,
Bpl.Expr allowance,
Expression receiverReplacement, Dictionary<IVariable,Expression> substMap,
+ Dictionary<TypeParameter, Type> typeMap,
ExpressionTranslator etranCurrent, ExpressionTranslator etranInitial, Bpl.StmtListBuilder builder, bool inferredDecreases, string hint) {
Contract.Requires(tok != null);
Contract.Requires(cce.NonNullElements(contextDecreases));
@@ -8835,7 +9082,7 @@ namespace Microsoft.Dafny {
tok = new ForceCheckToken(tok);
}
for (int i = 0; i < N; i++) {
- Expression e0 = Substitute(calleeDecreases[i], receiverReplacement, substMap);
+ Expression e0 = Substitute(calleeDecreases[i], receiverReplacement, substMap, typeMap);
Expression e1 = contextDecreases[i];
if (!CompatibleDecreasesTypes(e0.Type, e1.Type)) {
N = i;
@@ -9049,9 +9296,9 @@ namespace Microsoft.Dafny {
less = Bpl.Expr.Gt(e0, e1);
atmost = Bpl.Expr.Ge(e0, e1);
- } else if (ty0 is SetType || (ty0 is MapType && ((MapType)ty0).Finite)) {
+ } else if ((ty0 is SetType && ((SetType)ty0).Finite) || (ty0 is MapType && ((MapType)ty0).Finite)) {
Bpl.Expr b0, b1;
- if (ty0 is SetType) {
+ if (ty0 is SetType && ((SetType)ty0).Finite) {
b0 = e0;
b1 = e1;
} else if (ty0 is MapType && ((MapType)ty0).Finite) {
@@ -9130,40 +9377,41 @@ namespace Microsoft.Dafny {
Contract.Requires(type != null);
Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
- type = type.NormalizeExpand();
-
- if (type is SetType) {
- return FunctionCall(Token.NoToken, "TSet", predef.Ty, TypeToTy(((CollectionType)type).Arg));
- } else if (type is MultiSetType) {
- return FunctionCall(Token.NoToken, "TMultiSet", predef.Ty, TypeToTy(((CollectionType)type).Arg));
- } else if (type is SeqType) {
- return FunctionCall(Token.NoToken, "TSeq", predef.Ty, TypeToTy(((CollectionType)type).Arg));
- } else if (type is MapType) {
- bool finite = ((MapType)type).Finite;
+ var normType = type.NormalizeExpand();
+
+ if (normType is SetType) {
+ bool finite = ((SetType)normType).Finite;
+ return FunctionCall(Token.NoToken, finite ? "TSet" : "TISet", predef.Ty, TypeToTy(((CollectionType)normType).Arg));
+ } else if (normType is MultiSetType) {
+ return FunctionCall(Token.NoToken, "TMultiSet", predef.Ty, TypeToTy(((CollectionType)normType).Arg));
+ } else if (normType is SeqType) {
+ return FunctionCall(Token.NoToken, "TSeq", predef.Ty, TypeToTy(((CollectionType)normType).Arg));
+ } else if (normType is MapType) {
+ bool finite = ((MapType)normType).Finite;
return FunctionCall(Token.NoToken, finite ? "TMap" : "TIMap", predef.Ty,
- TypeToTy(((MapType)type).Domain),
- TypeToTy(((MapType)type).Range));
- } else if (type is BoolType) {
+ TypeToTy(((MapType)normType).Domain),
+ TypeToTy(((MapType)normType).Range));
+ } else if (normType is BoolType) {
return new Bpl.IdentifierExpr(Token.NoToken, "TBool", predef.Ty);
- } else if (type is CharType) {
+ } else if (normType is CharType) {
return new Bpl.IdentifierExpr(Token.NoToken, "TChar", predef.Ty);
- } else if (type is RealType) {
+ } else if (normType is RealType) {
return new Bpl.IdentifierExpr(Token.NoToken, "TReal", predef.Ty);
- } else if (type is NatType) {
+ } else if (normType is NatType) {
// (Nat needs to come before Int)
return new Bpl.IdentifierExpr(Token.NoToken, "TNat", predef.Ty);
- } else if (type is IntType) {
+ } else if (normType is IntType) {
return new Bpl.IdentifierExpr(Token.NoToken, "TInt", predef.Ty);
- } else if (type.IsTypeParameter) {
- return trTypeParam(type.AsTypeParameter, type.TypeArgs);
- } else if (type is ObjectType) {
+ } else if (normType.IsTypeParameter) {
+ return trTypeParam(normType.AsTypeParameter, normType.TypeArgs);
+ } else if (normType is ObjectType) {
return ClassTyCon(program.BuiltIns.ObjectDecl, new List<Bpl.Expr>());
- } else if (type is UserDefinedType) {
+ } else if (normType is UserDefinedType) {
// Classes, (co-)datatypes
- var args = type.TypeArgs.ConvertAll(TypeToTy);
- return ClassTyCon(((UserDefinedType)type), args);
- } else if (type is ParamTypeProxy) {
- return trTypeParam(((ParamTypeProxy)type).orig, null);
+ var args = normType.TypeArgs.ConvertAll(TypeToTy);
+ return ClassTyCon(((UserDefinedType)normType), args);
+ } else if (normType is ParamTypeProxy) {
+ return trTypeParam(((ParamTypeProxy)normType).orig, null);
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
}
@@ -9266,19 +9514,19 @@ namespace Microsoft.Dafny {
Contract.Requires(etran != null);
Contract.Requires(predef != null);
- type = type.NormalizeExpand();
- if (type is TypeProxy) {
+ var normType = type.NormalizeExpand();
+ if (normType is TypeProxy) {
// Unresolved proxy
// Omit where clause (in other places, unresolved proxies are treated as a reference type; we could do that here too, but
// we might as well leave out the where clause altogether).
return null;
}
- if (type is NatType) {
+ if (normType is NatType) {
// nat:
// 0 <= x
return Bpl.Expr.Le(Bpl.Expr.Literal(0), x);
- } else if (type is BoolType || type is IntType || type is RealType) {
+ } else if (normType is BoolType || normType is IntType || normType is RealType) {
// nothing to do
return null;
/* } else if (type is ArrowType) {
@@ -9286,7 +9534,7 @@ namespace Microsoft.Dafny {
return null;
*/
} else {
- return BplAnd(MkIs(x, type), MkIsAlloc(x, type, etran.HeapExpr));
+ return BplAnd(MkIs(x, normType), MkIsAlloc(x, normType, etran.HeapExpr));
}
}
@@ -9692,7 +9940,7 @@ namespace Microsoft.Dafny {
} else if (rhs is HavocRhs) {
builder.Add(new Bpl.HavocCmd(tok, new List<Bpl.IdentifierExpr> { bLhs }));
var isNat = CheckSubrange_Expr(tok, bLhs, rhsTypeConstraint);
- builder.Add(new Bpl.AssumeCmd(tok, isNat));
+ builder.Add(TrAssumeCmd(tok, isNat));
return CondApplyBox(tok, bLhs, rhsTypeConstraint, lhsType);
} else {
// x := new Something
@@ -9717,13 +9965,13 @@ namespace Microsoft.Dafny {
Bpl.Expr nwNotNull = Bpl.Expr.Neq(nw, predef.Null);
Bpl.Expr rightType;
rightType = etran.GoodRef_(tok, nw, tRhs.Type, true);
- builder.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.And(nwNotNull, rightType)));
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.And(nwNotNull, rightType)));
if (tRhs.ArrayDimensions != null) {
int i = 0;
foreach (Expression dim in tRhs.ArrayDimensions) {
// assume Array#Length($nw, i) == arraySize;
Bpl.Expr arrayLength = ArrayLength(tok, nw, tRhs.ArrayDimensions.Count, i);
- builder.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.Eq(arrayLength, etran.TrExpr(dim))));
+ builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(arrayLength, etran.TrExpr(dim))));
i++;
}
}
@@ -9829,7 +10077,7 @@ namespace Microsoft.Dafny {
Contract.Requires(etran != null);
Contract.Ensures(Contract.Result<AssumeCmd>() != null);
- return new Bpl.AssumeCmd(tok, FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr));
+ return TrAssumeCmd(tok, FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr));
}
/// <summary>
@@ -9862,7 +10110,7 @@ namespace Microsoft.Dafny {
var FVs = new HashSet<IVariable>();
bool usesHeap = false, usesOldHeap = false;
Type usesThis = null;
- ComputeFreeVariables(e.RHSs[0], FVs, ref usesHeap, ref usesOldHeap, ref usesThis, false);
+ ComputeFreeVariables(e.RHSs[0], FVs, ref usesHeap, ref usesOldHeap, ref usesThis);
foreach (var bv in e.BoundVars) {
FVs.Remove(bv);
}
@@ -10152,6 +10400,293 @@ namespace Microsoft.Dafny {
}
}
+ internal class FuelSettingPair
+ {
+ public int low;
+ public int high;
+
+ public FuelSettingPair(int low = (int)FuelSetting.FuelAmount.LOW, int high = (int)FuelSetting.FuelAmount.HIGH) {
+ this.low = low;
+ this.high = high;
+ }
+ }
+
+ // C#'s version of a type alias
+ internal class FuelContext : Dictionary<Function, FuelSettingPair> { }
+
+ internal class FuelConstant
+ {
+ public Function f;
+ public Bpl.Expr baseFuel;
+ public Bpl.Expr startFuel;
+ public Bpl.Expr startFuelAssert;
+
+ public FuelConstant(Function f, Bpl.Expr baseFuel, Bpl.Expr startFuel, Bpl.Expr startFuelAssert) {
+ this.f = f;
+ this.baseFuel = baseFuel;
+ this.startFuel = startFuel;
+ this.startFuelAssert = startFuelAssert;
+ }
+
+ public Bpl.Expr MoreFuel(Bpl.Program sink, PredefinedDecls predef, FreshIdGenerator idGen) {
+ string uniqueId = idGen.FreshId("MoreFuel_" + f.FullName);
+ Bpl.Constant moreFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, uniqueId, predef.LayerType), false);
+ sink.AddTopLevelDeclaration(moreFuel);
+ Bpl.Expr moreFuel_expr = new Bpl.IdentifierExpr(f.tok, moreFuel);
+ return moreFuel_expr;
+ }
+ }
+
+ internal class FuelSetting
+ {
+ public enum FuelAmount { NONE, LOW, HIGH };
+ public static Stack<FuelContext> SavedContexts = new Stack<FuelContext>();
+
+ public static FuelSettingPair FuelAttrib(Function f, out bool found) {
+ Contract.Requires(f != null);
+ Contract.Ensures(Contract.Result<FuelSettingPair>() != null);
+ FuelSettingPair setting = new FuelSettingPair();
+ found = false;
+
+ if (f.Attributes != null) {
+ List<Expression> args = Attributes.FindExpressions(f.Attributes, "fuel");
+ if (args != null) {
+ found = true;
+ if (args.Count >= 2) {
+ LiteralExpr literalLow = args[0] as LiteralExpr;
+ LiteralExpr literalHigh = args[1] as LiteralExpr;
+
+ if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) {
+ setting.low = (int)((BigInteger)literalLow.Value);
+ setting.high = (int)((BigInteger)literalHigh.Value);
+ }
+ } else if (args.Count >= 1) {
+ LiteralExpr literal = args[0] as LiteralExpr;
+ if (literal != null && literal.Value is BigInteger) {
+ setting.low = (int)((BigInteger)literal.Value);
+ setting.high = setting.low + 1;
+ }
+ }
+ }
+ }
+
+ return setting;
+ }
+
+ public int amount; // Amount of fuel above that represented by start
+ private Bpl.Expr start; // Starting fuel argument (null indicates LZ)
+ private Translator translator;
+
+ public FuelSetting(Translator translator, int amount, Bpl.Expr start = null) {
+ this.translator = translator;
+ this.amount = amount;
+ this.start = start;
+ }
+
+ public FuelSetting Offset(int offset) {
+ return new FuelSetting(translator, this.amount + offset, start);
+ }
+
+ public Bpl.Expr LayerZero() {
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+ return new Bpl.IdentifierExpr(Token.NoToken, "$LZ", translator.predef.LayerType);
+ }
+
+ public Bpl.Expr LayerN(int n) {
+ Contract.Requires(0 <= n);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+ return translator.LayerSucc(LayerZero(), n);
+ }
+
+ public Bpl.Expr LayerN(int n, Bpl.Expr baseLayer) {
+ Contract.Requires(0 <= n);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+ return translator.LayerSucc(baseLayer, n);
+ }
+
+ private Bpl.Expr ToExpr(int amount) {
+ if (start == null) {
+ return LayerN(amount);
+ } else {
+ return translator.LayerSucc(start, amount);
+ }
+ }
+
+ public Bpl.Expr ToExpr() {
+ return this.ToExpr(this.amount);
+ }
+
+ /// <summary>
+ /// Get the fuel value for this function, given the ambient environment (represented by the fuel setting)
+ /// the function itself, and the function call's context (if any)
+ /// </summary>
+ public Bpl.Expr GetFunctionFuel(Function f) {
+ Contract.Requires(f != null);
+ if (this.amount == (int)FuelAmount.NONE) {
+ return this.ToExpr();
+ } else {
+ FuelSettingPair setting = null;
+ var found = translator.fuelContext.TryGetValue(f, out setting);
+
+ if (!found) { // If the context doesn't define fuel for this function, check for a fuel attribute (which supplies a default value if none is found)
+ setting = FuelAttrib(f, out found);
+ }
+
+ FuelConstant fuelConstant = translator.functionFuel.Find(x => x.f == f);
+ if (this.amount == (int)FuelAmount.LOW) {
+ return GetFunctionFuel(setting.low, found, fuelConstant);
+ } else if (this.amount == (int)FuelAmount.HIGH) {
+ return GetFunctionFuel(setting.high, found, fuelConstant);
+ } else {
+ Contract.Assert(false); // Should not reach here
+ return null;
+ }
+ }
+ }
+
+ private Bpl.Expr GetFunctionFuel(int amount, bool hasFuel, FuelConstant fuelConstant) {
+ if (fuelConstant != null) {
+ if (hasFuel) {
+ // it has fuel context
+ return LayerN(amount, fuelConstant.baseFuel);
+ } else {
+ // startfuel
+ if (amount == (int)FuelAmount.LOW) {
+ return fuelConstant.startFuel;
+ } else {
+ return fuelConstant.startFuelAssert;
+ }
+ }
+ } else {
+ return ToExpr(amount);
+ }
+ }
+
+ /// <summary>
+ /// Finds all fuel related attributes of the form {:fuel function low [high]}
+ /// Adds the setting to the context _if_ the context does not already have a setting for that function.
+ /// In other words, it should be called in order from most to least specific contenxt scope.
+ /// </summary>
+ public static void FindFuelAttributes(Attributes attribs, FuelContext fuelContext) {
+ Function f = null;
+ FuelSettingPair setting = null;
+
+ if (attribs != null) {
+ List<List<Expression>> results = Attributes.FindAllExpressions(attribs, "fuel");
+
+ if (results != null) {
+ foreach (List<Expression> args in results) {
+ if (args != null && args.Count >= 2) {
+ // Try to extract the function from the first argument
+ MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;
+ if (selectExpr != null) {
+ f = selectExpr.Member as Function;
+ }
+
+ // Try to extract the lower fuel setting
+ LiteralExpr literalLow = args[1] as LiteralExpr;
+ if (literalLow != null && literalLow.Value is BigInteger) {
+ setting = new FuelSettingPair();
+ setting.low = (int)((BigInteger)literalLow.Value);
+ }
+
+ // The user may supply an additional high argument; if not, it defaults to low + 1
+ if (f != null && args.Count >= 3) {
+ LiteralExpr literalHigh = args[2] as LiteralExpr;
+ if (setting != null && literalHigh != null && literalHigh.Value is BigInteger) {
+ setting.high = (int)((BigInteger)literalHigh.Value);
+ if (!fuelContext.ContainsKey(f)) {
+ fuelContext.Add(f, setting);
+ }
+ }
+ } else if (f != null && setting != null) {
+ setting.high = setting.low + 1;
+ if (!fuelContext.ContainsKey(f)) {
+ fuelContext.Add(f, setting);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Extend the given context with fuel information from the declaration itself, and enclosing modules
+ /// </summary>
+ private static void AddFuelContext(FuelContext context, TopLevelDecl decl) {
+ FindFuelAttributes(decl.Attributes, context);
+
+ var module = decl.Module;
+ while (module != null) {
+ FindFuelAttributes(module.Attributes, context);
+ module = module.Module;
+ }
+ }
+
+ /// <summary>
+ /// Creates a summary of all fuel settings in scope, starting from the given class declaration
+ /// </summary>
+ public static FuelContext NewFuelContext(TopLevelDecl decl) {
+ FuelContext context = new FuelContext();
+ AddFuelContext(context, decl);
+ return context;
+ }
+
+ /// <summary>
+ /// Creates a summary of all fuel settings in scope, starting from the given member declaration
+ /// </summary>
+ public static FuelContext NewFuelContext(MemberDecl decl) {
+ FuelContext context = new FuelContext();
+
+ FindFuelAttributes(decl.Attributes, context);
+ AddFuelContext(context, decl.EnclosingClass);
+
+ return context;
+ }
+
+ /// <summary>
+ /// Extends the given fuel context with any new fuel settings found in attribs
+ /// </summary>
+ public static FuelContext ExpandFuelContext(Attributes attribs, IToken tok, FuelContext oldFuelContext, ErrorReporter reporter) {
+ Contract.Ensures(SavedContexts.Count == Contract.OldValue(SavedContexts.Count) + 1);
+ FuelContext newContext = new FuelContext();
+ FindFuelAttributes(attribs, newContext);
+ if (newContext.Count > 0) {
+ // first make sure that the fuel only increase relative to the oldContext
+ foreach (var pair in newContext) {
+ FuelSettingPair newSetting = pair.Value;
+ FuelSettingPair oldSetting;
+ var found = oldFuelContext.TryGetValue(pair.Key, out oldSetting);
+ if (!found) { // the default is {:fuel, 1, 2}
+ oldSetting = new FuelSettingPair();
+ }
+ // make sure that the fuel can only increase within a given scope
+ if (newSetting.low < oldSetting.low || newSetting.high < oldSetting.high) {
+ reporter.Error(MessageSource.Translator, tok, "Fuel can only increase within a given scope.");
+ }
+ }
+ // add oldContext to newContext if it doesn't exist already
+ foreach (var pair in oldFuelContext) {
+ if (!newContext.ContainsKey(pair.Key)) { // Local setting takes precedence over old context
+ newContext.Add(pair.Key, pair.Value);
+ }
+ }
+ } else {
+ newContext = oldFuelContext;
+ }
+ SavedContexts.Push(oldFuelContext);
+
+ return newContext;
+ }
+
+ public static FuelContext PopFuelContext() {
+ Contract.Requires(SavedContexts.Count > 0);
+ return SavedContexts.Pop();
+ }
+
+ }
+
internal class ExpressionTranslator
{
public readonly Bpl.Expr HeapExpr;
@@ -10160,10 +10695,10 @@ namespace Microsoft.Dafny {
public readonly string This;
public readonly string modifiesFrame; // the name of the context's frame variable.
readonly Function applyLimited_CurrentFunction;
- public readonly Bpl.Expr layerInterCluster;
- public readonly Bpl.Expr layerIntraCluster = null; // a value of null says to do the same as for inter-cluster calls
+ public readonly FuelSetting layerInterCluster;
+ public readonly FuelSetting layerIntraCluster = null; // a value of null says to do the same as for inter-cluster calls
public int Statistics_CustomLayerFunctionCount = 0;
- public readonly bool ProducingCoCertificates = false;
+ public readonly bool stripLits = false;
[ContractInvariantMethod]
void ObjectInvariant()
{
@@ -10178,40 +10713,16 @@ namespace Microsoft.Dafny {
}
/// <summary>
- /// This is a general constructor, but takes the layerInterCluster as an int.
- /// </summary>
- ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar,
- Function applyLimited_CurrentFunction, int layerInterCluster, Bpl.Expr layerIntraCluster, string modifiesFrame) {
-
- Contract.Requires(translator != null);
- Contract.Requires(predef != null);
- Contract.Requires(heap != null);
- Contract.Requires(thisVar != null);
- Contract.Requires(0 <= layerInterCluster);
- Contract.Requires(modifiesFrame != null);
-
- this.translator = translator;
- this.predef = predef;
- this.HeapExpr = heap;
- this.This = thisVar;
- this.applyLimited_CurrentFunction = applyLimited_CurrentFunction;
- this.layerInterCluster = LayerN(layerInterCluster);
- this.layerIntraCluster = layerIntraCluster;
- this.modifiesFrame = modifiesFrame;
- }
-
- /// <summary>
/// This is the most general constructor. It is private and takes all the parameters. Whenever
/// one ExpressionTranslator is constructed from another, unchanged parameters are just copied in.
/// </summary>
ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar,
- Function applyLimited_CurrentFunction, Bpl.Expr layerInterCluster, Bpl.Expr layerIntraCluster, string modifiesFrame) {
+ Function applyLimited_CurrentFunction, FuelSetting layerInterCluster, FuelSetting layerIntraCluster, string modifiesFrame, bool stripLits) {
Contract.Requires(translator != null);
Contract.Requires(predef != null);
Contract.Requires(heap != null);
- Contract.Requires(thisVar != null);
- Contract.Requires(layerInterCluster != null);
+ Contract.Requires(thisVar != null);
Contract.Requires(modifiesFrame != null);
this.translator = translator;
@@ -10226,6 +10737,7 @@ namespace Microsoft.Dafny {
this.layerIntraCluster = layerIntraCluster;
}
this.modifiesFrame = modifiesFrame;
+ this.stripLits = stripLits;
}
public ExpressionTranslator(Translator translator, PredefinedDecls predef, IToken heapToken)
@@ -10255,7 +10767,7 @@ namespace Microsoft.Dafny {
}
public ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar)
- : this(translator, predef, heap, thisVar, null, 1, null, "$_Frame") {
+ : this(translator, predef, heap, thisVar, null, new FuelSetting(translator, 1), null, "$_Frame", false) {
Contract.Requires(translator != null);
Contract.Requires(predef != null);
Contract.Requires(heap != null);
@@ -10263,14 +10775,14 @@ namespace Microsoft.Dafny {
}
public ExpressionTranslator(ExpressionTranslator etran, Bpl.Expr heap)
- : this(etran.translator, etran.predef, heap, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, etran.modifiesFrame)
+ : this(etran.translator, etran.predef, heap, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, etran.modifiesFrame, etran.stripLits)
{
Contract.Requires(etran != null);
Contract.Requires(heap != null);
}
public ExpressionTranslator(ExpressionTranslator etran, string modifiesFrame)
- : this(etran.translator, etran.predef, etran.HeapExpr, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, modifiesFrame) {
+ : this(etran.translator, etran.predef, etran.HeapExpr, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, modifiesFrame, etran.stripLits) {
Contract.Requires(etran != null);
Contract.Requires(modifiesFrame != null);
}
@@ -10281,7 +10793,7 @@ namespace Microsoft.Dafny {
Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);
if (oldEtran == null) {
- oldEtran = new ExpressionTranslator(translator, predef, new Bpl.OldExpr(HeapExpr.tok, HeapExpr), This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame);
+ oldEtran = new ExpressionTranslator(translator, predef, new Bpl.OldExpr(HeapExpr.tok, HeapExpr), This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, stripLits);
oldEtran.oldEtran = oldEtran;
}
return oldEtran;
@@ -10299,7 +10811,12 @@ namespace Microsoft.Dafny {
Contract.Requires(layerArgument != null);
Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);
- return new ExpressionTranslator(translator, predef, HeapExpr, This, null, layerArgument, layerArgument, modifiesFrame);
+ return new ExpressionTranslator(translator, predef, HeapExpr, This, null, new FuelSetting(translator, 0, layerArgument), new FuelSetting(translator, 0, layerArgument), modifiesFrame, stripLits);
+ }
+
+ public ExpressionTranslator WithNoLits() {
+ Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);
+ return new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, true);
}
public ExpressionTranslator LimitedFunctions(Function applyLimited_CurrentFunction, Bpl.Expr layerArgument) {
@@ -10307,16 +10824,16 @@ namespace Microsoft.Dafny {
Contract.Requires(layerArgument != null);
Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);
- return new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, /* layerArgument */ layerInterCluster, layerArgument, modifiesFrame);
+ return new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, /* layerArgument */ layerInterCluster, new FuelSetting(translator, 0, layerArgument), modifiesFrame, stripLits);
}
public ExpressionTranslator LayerOffset(int offset) {
Contract.Requires(0 <= offset);
Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);
- var et = new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, translator.LayerSucc(layerInterCluster, offset), layerIntraCluster, modifiesFrame);
+ var et = new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster.Offset(offset), layerIntraCluster, modifiesFrame, stripLits);
if (this.oldEtran != null) {
- var etOld = new ExpressionTranslator(translator, predef, Old.HeapExpr, This, applyLimited_CurrentFunction, translator.LayerSucc(layerInterCluster, offset), layerIntraCluster, modifiesFrame);
+ var etOld = new ExpressionTranslator(translator, predef, Old.HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster.Offset(offset), layerIntraCluster, modifiesFrame, stripLits);
etOld.oldEtran = etOld;
et.oldEtran = etOld;
}
@@ -10355,17 +10872,6 @@ namespace Microsoft.Dafny {
}
}
- public Bpl.Expr LayerZero() {
- Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
- return new Bpl.IdentifierExpr(Token.NoToken, "$LZ", predef.LayerType);
- }
-
- public Bpl.Expr LayerN(int n) {
- Contract.Requires(0 <= n);
- Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
- return translator.LayerSucc(LayerZero(), n);
- }
-
public Bpl.IdentifierExpr ModuleContextHeight() {
Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>().Type != null);
return new Bpl.IdentifierExpr(Token.NoToken, "$ModuleContextHeight", Bpl.Type.Int);
@@ -10399,13 +10905,24 @@ namespace Microsoft.Dafny {
return translator.Substitute(e.Body, null, substMap);
}
+ public Expr MaybeLit(Expr expr, Bpl.Type type) {
+ return stripLits ? expr : translator.Lit(expr, type);
+ }
+
+ public Expr MaybeLit(Expr expr) {
+ return stripLits ? expr : translator.Lit(expr);
+ }
+
/// <summary>
/// Translates Dafny expression "expr" into a Boogie expression. If the type of "expr" can be a boolean, then the
/// token (source location) of the resulting expression is filled in (it wouldn't hurt if the token were always
/// filled in, but it is really necessary for anything that may show up in a Boogie assert, since that location may
/// then show up in an error message).
/// </summary>
- public Bpl.Expr TrExpr(Expression expr)
+ public Bpl.Expr TrExpr(Expression expr) {
+ return TrExpr(expr, null, null, null);
+ }
+ public Bpl.Expr TrExpr(Expression expr, ExpressionTranslator initEtran, ExpressionTranslator funcEtran, ExpressionTranslator existEtran)
{
Contract.Requires(expr != null);
Contract.Requires(predef != null);
@@ -10415,7 +10932,7 @@ namespace Microsoft.Dafny {
if (e.Value == null) {
return predef.Null;
} else if (e.Value is bool) {
- return translator.Lit(new Bpl.LiteralExpr(e.tok, (bool)e.Value));
+ return MaybeLit(new Bpl.LiteralExpr(e.tok, (bool)e.Value));
} else if (e is CharLiteralExpr) {
// we expect e.Value to be a string representing exactly one char
Bpl.Expr rawElement = null; // assignment to please compiler's definite assignment rule
@@ -10424,7 +10941,7 @@ namespace Microsoft.Dafny {
rawElement = translator.FunctionCall(expr.tok, BuiltinFunction.CharFromInt, null, Bpl.Expr.Literal((int)ch));
}
Contract.Assert(rawElement != null); // there should have been an iteration of the loop above
- return translator.Lit(rawElement, predef.CharType);
+ return MaybeLit(rawElement, predef.CharType);
} else if (e is StringLiteralExpr) {
var str = (StringLiteralExpr)e;
Bpl.Expr seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqEmpty, predef.BoxType);
@@ -10433,11 +10950,11 @@ namespace Microsoft.Dafny {
Bpl.Expr elt = BoxIfNecessary(expr.tok, rawElement, Type.Char);
seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, seq, elt);
}
- return translator.Lit(seq, translator.TrType(new SeqType(Type.Char)));
+ return MaybeLit(seq, translator.TrType(new SeqType(Type.Char)));
} else if (e.Value is BigInteger) {
- return translator.Lit(Bpl.Expr.Literal(Microsoft.Basetypes.BigNum.FromBigInt((BigInteger)e.Value)));
+ return MaybeLit(Bpl.Expr.Literal(Microsoft.Basetypes.BigNum.FromBigInt((BigInteger)e.Value)));
} else if (e.Value is Basetypes.BigDec) {
- return translator.Lit(Bpl.Expr.Literal((Basetypes.BigDec)e.Value));
+ return MaybeLit(Bpl.Expr.Literal((Basetypes.BigDec)e.Value));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected literal
}
@@ -10469,16 +10986,16 @@ namespace Microsoft.Dafny {
args.Add(Old.HeapExpr);
}
foreach (var arg in e.Args) {
- args.Add(TrExpr(arg));
+ args.Add(TrExpr(arg, initEtran, funcEtran, existEtran));
}
return new Bpl.NAryExpr(e.tok, new Bpl.FunctionCall(id), args);
} else if (expr is SetDisplayExpr) {
SetDisplayExpr e = (SetDisplayExpr)expr;
- Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.SetEmpty, predef.BoxType);
+ Bpl.Expr s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.SetEmpty : BuiltinFunction.ISetEmpty, predef.BoxType);
foreach (Expression ee in e.Elements) {
- Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee), cce.NonNull(ee.Type));
- s = translator.FunctionCall(expr.tok, BuiltinFunction.SetUnionOne, predef.BoxType, s, ss);
+ Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee, initEtran, funcEtran, existEtran), cce.NonNull(ee.Type));
+ s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.SetUnionOne : BuiltinFunction.ISetUnionOne, predef.BoxType, s, ss);
}
return s;
@@ -10486,7 +11003,7 @@ namespace Microsoft.Dafny {
MultiSetDisplayExpr e = (MultiSetDisplayExpr)expr;
Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEmpty, predef.BoxType);
foreach (Expression ee in e.Elements) {
- Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee), cce.NonNull(ee.Type));
+ Bpl.Expr ss = BoxIfNecessary(expr.tok, TrExpr(ee, initEtran, funcEtran, existEtran), cce.NonNull(ee.Type));
s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetUnionOne, predef.BoxType, s, ss);
}
return s;
@@ -10497,13 +11014,14 @@ namespace Microsoft.Dafny {
Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqEmpty, predef.BoxType);
bool isLit = true;
foreach (Expression ee in e.Elements) {
- var rawElement = TrExpr(ee);
+ var rawElement = TrExpr(ee, initEtran, funcEtran, existEtran);
isLit = isLit && translator.IsLit(rawElement);
Bpl.Expr elt = BoxIfNecessary(expr.tok, rawElement, ee.Type);
s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, s, elt);
}
if (isLit) {
- s = translator.Lit(s, predef.BoxType);
+ // Lit-lifting: All elements are lit, so the sequence is Lit too
+ s = MaybeLit(s, predef.BoxType);
}
return s;
@@ -10512,8 +11030,8 @@ namespace Microsoft.Dafny {
Bpl.Type maptype = predef.MapType(expr.tok, e.Finite, predef.BoxType, predef.BoxType);
Bpl.Expr s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.MapEmpty : BuiltinFunction.IMapEmpty, predef.BoxType);
foreach (ExpressionPair p in e.Elements) {
- Bpl.Expr elt = BoxIfNecessary(expr.tok, TrExpr(p.A), cce.NonNull(p.A.Type));
- Bpl.Expr elt2 = BoxIfNecessary(expr.tok, TrExpr(p.B), cce.NonNull(p.B.Type));
+ Bpl.Expr elt = BoxIfNecessary(expr.tok, TrExpr(p.A, initEtran, funcEtran, existEtran), cce.NonNull(p.A.Type));
+ Bpl.Expr elt2 = BoxIfNecessary(expr.tok, TrExpr(p.B, initEtran, funcEtran, existEtran), cce.NonNull(p.B.Type));
s = translator.FunctionCall(expr.tok, e.Finite ? "Map#Build" : "IMap#Build", maptype, s, elt, elt2);
}
return s;
@@ -10522,7 +11040,7 @@ namespace Microsoft.Dafny {
var e = (MemberSelectExpr)expr;
return e.MemberSelectCase(
field => {
- Bpl.Expr obj = TrExpr(e.Obj);
+ Bpl.Expr obj = TrExpr(e.Obj, initEtran, funcEtran, existEtran);
Bpl.Expr result;
if (field.IsMutable) {
result = ReadHeap(expr.tok, HeapExpr, obj, new Bpl.IdentifierExpr(expr.tok, translator.GetField(field)));
@@ -10532,15 +11050,15 @@ namespace Microsoft.Dafny {
new List<Bpl.Expr> {obj});
result = translator.CondApplyUnbox(expr.tok, result, field.Type, expr.Type);
if (translator.IsLit(obj)) {
- result = translator.Lit(result, translator.TrType(expr.Type));
+ result = MaybeLit(result, translator.TrType(expr.Type));
}
return result;
}
},
fn => {
var args = e.TypeApplication.ConvertAll(translator.TypeToTy);
- if (fn.IsRecursive) {
- args.Add(layerInterCluster);
+ if (fn.IsFuelAware()) {
+ args.Add(this.layerInterCluster.GetFunctionFuel(fn));
}
if (!fn.IsStatic) {
args.Add(/* translator.BoxIfUnboxed */(TrExpr(e.Obj)/*, e.Type */));
@@ -10549,7 +11067,7 @@ namespace Microsoft.Dafny {
});
} else if (expr is SeqSelectExpr) {
SeqSelectExpr e = (SeqSelectExpr)expr;
- Bpl.Expr seq = TrExpr(e.Seq);
+ Bpl.Expr seq = TrExpr(e.Seq, initEtran, funcEtran, existEtran);
var seqType = e.Seq.Type.NormalizeExpand();
Type elmtType = null;
Type domainType = null;
@@ -10569,14 +11087,14 @@ namespace Microsoft.Dafny {
} else { Contract.Assert(false); }
Bpl.Type elType = translator.TrType(elmtType);
Bpl.Type dType = translator.TrType(domainType);
- Bpl.Expr e0 = e.E0 == null ? null : TrExpr(e.E0);
- Bpl.Expr e1 = e.E1 == null ? null : TrExpr(e.E1);
+ Bpl.Expr e0 = e.E0 == null ? null : TrExpr(e.E0, initEtran, funcEtran, existEtran);
+ Bpl.Expr e1 = e.E1 == null ? null : TrExpr(e.E1, initEtran, funcEtran, existEtran);
if (e.SelectOne) {
Contract.Assert(e1 == null);
Bpl.Expr x;
if (seqType.IsArrayType) {
Bpl.Expr fieldName = translator.FunctionCall(expr.tok, BuiltinFunction.IndexField, null, e0);
- x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Seq), fieldName);
+ x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Seq, initEtran, funcEtran, existEtran), fieldName);
} else if (seqType is SeqType) {
x = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.BoxType, seq, e0);
} else if (seqType is MapType) {
@@ -10585,7 +11103,7 @@ namespace Microsoft.Dafny {
x = translator.FunctionCall(expr.tok, f, predef.MapType(e.tok, finite, predef.BoxType, predef.BoxType), seq);
x = Bpl.Expr.Select(x, BoxIfNecessary(e.tok, e0, domainType));
} else if (seqType is MultiSetType) {
- x = Bpl.Expr.SelectTok(expr.tok, TrExpr(e.Seq), BoxIfNecessary(expr.tok, e0, domainType));
+ x = Bpl.Expr.SelectTok(expr.tok, TrExpr(e.Seq, initEtran, funcEtran, existEtran), BoxIfNecessary(expr.tok, e0, domainType));
} else { Contract.Assert(false); x = null; }
if (!ModeledAsBoxType(elmtType) && !(seqType is MultiSetType)) {
x = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, elType, x);
@@ -10607,7 +11125,7 @@ namespace Microsoft.Dafny {
// if e0 == null && e1 == null, then we have the identity operation seq[..] == seq;
if (isLit && (e0 != null || e1 != null)) {
// Lit-lift the expression
- seq = translator.Lit(seq, translator.TrType(expr.Type));
+ seq = MaybeLit(seq, translator.TrType(expr.Type));
}
return seq;
}
@@ -10616,32 +11134,32 @@ namespace Microsoft.Dafny {
SeqUpdateExpr e = (SeqUpdateExpr)expr;
if (e.ResolvedUpdateExpr != null)
{
- return TrExpr(e.ResolvedUpdateExpr);
+ return TrExpr(e.ResolvedUpdateExpr, initEtran, funcEtran, existEtran);
}
else
{
- Bpl.Expr seq = TrExpr(e.Seq);
+ Bpl.Expr seq = TrExpr(e.Seq, initEtran, funcEtran, existEtran);
var seqType = e.Seq.Type.NormalizeExpand();
if (seqType is SeqType)
{
Type elmtType = cce.NonNull((SeqType)seqType).Arg;
- Bpl.Expr index = TrExpr(e.Index);
- Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value), elmtType);
+ Bpl.Expr index = TrExpr(e.Index, initEtran, funcEtran, existEtran);
+ Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value, initEtran, funcEtran, existEtran), elmtType);
return translator.FunctionCall(expr.tok, BuiltinFunction.SeqUpdate, predef.BoxType, seq, index, val);
}
else if (seqType is MapType)
{
MapType mt = (MapType)seqType;
Bpl.Type maptype = predef.MapType(expr.tok, mt.Finite, predef.BoxType, predef.BoxType);
- Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index), mt.Domain);
- Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value), mt.Range);
+ Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index, initEtran, funcEtran, existEtran), mt.Domain);
+ Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value, initEtran, funcEtran, existEtran), mt.Range);
return translator.FunctionCall(expr.tok, mt.Finite ? "Map#Build" : "IMap#Build", maptype, seq, index, val);
}
else if (seqType is MultiSetType)
{
Type elmtType = cce.NonNull((MultiSetType)seqType).Arg;
- Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index), elmtType);
- Bpl.Expr val = TrExpr(e.Value);
+ Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index, initEtran, funcEtran, existEtran), elmtType);
+ Bpl.Expr val = TrExpr(e.Value, initEtran, funcEtran, existEtran);
return Bpl.Expr.StoreTok(expr.tok, seq, index, val);
}
else
@@ -10657,7 +11175,7 @@ namespace Microsoft.Dafny {
Bpl.Type elType = translator.TrType(elmtType);
Bpl.Expr fieldName = GetArrayIndexFieldName(expr.tok, e.Indices);
- Bpl.Expr x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Array), fieldName);
+ Bpl.Expr x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Array, initEtran, funcEtran, existEtran), fieldName);
if (!ModeledAsBoxType(elmtType)) {
x = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, elType, x);
}
@@ -10681,67 +11199,82 @@ namespace Microsoft.Dafny {
Function = fn,
Type = e.Type,
TypeArgumentSubstitutions = Util.Dict(GetTypeParams(fn), mem.TypeApplication)
- });
+ }, initEtran, funcEtran, existEtran);
}
}
- Func<Expression, Bpl.Expr> TrArg = arg => translator.BoxIfUnboxed(TrExpr(arg), arg.Type);
+ Func<Expression, Bpl.Expr> TrArg = arg => translator.BoxIfUnboxed(TrExpr(arg, initEtran, funcEtran, existEtran), arg.Type);
var applied = translator.FunctionCall(expr.tok, translator.Apply(arity), predef.BoxType,
Concat(Map(tt.TypeArgs,translator.TypeToTy),
- Cons(TrExpr(e.Function), Cons(HeapExpr, e.Args.ConvertAll(arg => TrArg(arg))))));
+ Cons(TrExpr(e.Function, initEtran, funcEtran, existEtran), Cons(HeapExpr, e.Args.ConvertAll(arg => TrArg(arg))))));
return translator.UnboxIfBoxed(applied, tt.Result);
} else if (expr is FunctionCallExpr) {
FunctionCallExpr e = (FunctionCallExpr)expr;
Bpl.Expr layerArgument;
- if (e.Function.IsRecursive) {
+ var etran = this;
+ if (e.Function.ContainsQuantifier && funcEtran != null) {
+ etran = funcEtran;
+ }
+ if (e.Function.IsFuelAware()) {
Statistics_CustomLayerFunctionCount++;
ModuleDefinition module = e.Function.EnclosingClass.Module;
- if (this.applyLimited_CurrentFunction != null &&
- this.layerIntraCluster != null &&
+ if (etran.applyLimited_CurrentFunction != null &&
+ etran.layerIntraCluster != null &&
ModuleDefinition.InSameSCC(e.Function, applyLimited_CurrentFunction)) {
- layerArgument = this.layerIntraCluster;
+ layerArgument = etran.layerIntraCluster.GetFunctionFuel(e.Function);
} else {
- layerArgument = this.layerInterCluster;
+ layerArgument = etran.layerInterCluster.GetFunctionFuel(e.Function);
}
} else {
layerArgument = null;
}
var ty = translator.TrType(e.Type);
- var id = new Bpl.IdentifierExpr(e.tok, e.Function.FullSanitizedName, ty);
- bool returnLit;
- var args = FunctionInvocationArguments(e, layerArgument, out returnLit);
+ var name = e.Function.FullSanitizedName;
+ if (DafnyOptions.O.IronDafny) {
+ name = e.Function.FullSanitizedRefinementName;
+ }
+ var id = new Bpl.IdentifierExpr(e.tok, name, ty);
+ bool argsAreLit;
+ var args = FunctionInvocationArguments(e, layerArgument, out argsAreLit);
Expr result = new Bpl.NAryExpr(e.tok, new Bpl.FunctionCall(id), args);
result = translator.CondApplyUnbox(e.tok, result, e.Function.ResultType, e.Type);
- if (returnLit && Translator.FunctionBodyIsAvailable(e.Function, translator.currentModule)) {
- result = translator.Lit(result, ty);
+
+ bool callIsLit = argsAreLit
+ && Translator.FunctionBodyIsAvailable(e.Function, translator.currentModule, true)
+ && !e.Function.Reads.Any(); // Function could depend on external values
+ if (callIsLit) {
+ result = MaybeLit(result, ty);
}
+
return result;
} else if (expr is DatatypeValue) {
DatatypeValue dtv = (DatatypeValue)expr;
Contract.Assert(dtv.Ctor != null); // since dtv has been successfully resolved
List<Bpl.Expr> args = new List<Bpl.Expr>();
- bool isLit = true;
+
+ bool argsAreLit = true;
for (int i = 0; i < dtv.Arguments.Count; i++) {
Expression arg = dtv.Arguments[i];
Type t = dtv.Ctor.Formals[i].Type;
- var bArg = TrExpr(arg);
- isLit = isLit && translator.IsLit(bArg);
+ var bArg = TrExpr(arg, initEtran, funcEtran, existEtran);
+ argsAreLit = argsAreLit && translator.IsLit(bArg);
args.Add(translator.CondApplyBox(expr.tok, bArg, cce.NonNull(arg.Type), t));
}
Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(dtv.tok, dtv.Ctor.FullName, predef.DatatypeType);
Bpl.Expr ret = new Bpl.NAryExpr(dtv.tok, new Bpl.FunctionCall(id), args);
- if (isLit) {
- ret = translator.Lit(ret, predef.DatatypeType);
+ if (argsAreLit) {
+ // If all arguments are Lit, so is the whole expression
+ ret = MaybeLit(ret, predef.DatatypeType);
}
return ret;
} else if (expr is OldExpr) {
OldExpr e = (OldExpr)expr;
- return Old.TrExpr(e.E);
+ return Old.TrExpr(e.E, initEtran, funcEtran, existEtran);
} else if (expr is MultiSetFormingExpr) {
MultiSetFormingExpr e = (MultiSetFormingExpr)expr;
@@ -10756,17 +11289,17 @@ namespace Microsoft.Dafny {
} else if (expr is UnaryOpExpr) {
var e = (UnaryOpExpr)expr;
- Bpl.Expr arg = TrExpr(e.E);
+ Bpl.Expr arg = TrExpr(e.E, initEtran, funcEtran, existEtran);
switch (e.Op) {
case UnaryOpExpr.Opcode.Lit:
- return translator.Lit(arg);
+ return MaybeLit(arg);
case UnaryOpExpr.Opcode.Not:
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);
case UnaryOpExpr.Opcode.Cardinality:
var eType = e.E.Type.NormalizeExpand();
if (eType is SeqType) {
return translator.FunctionCall(expr.tok, BuiltinFunction.SeqLength, null, arg);
- } else if (eType is SetType) {
+ } else if (eType is SetType && ((SetType)eType).Finite) {
return translator.FunctionCall(expr.tok, BuiltinFunction.SetCard, null, arg);
} else if (eType is MultiSetType) {
return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetCard, null, arg);
@@ -10784,29 +11317,37 @@ namespace Microsoft.Dafny {
Bpl.Expr o = new Bpl.IdentifierExpr(expr.tok, oVar);
Bpl.Expr oNotNull = Bpl.Expr.Neq(o, predef.Null);
Bpl.Expr oInSet = TrInSet(expr.tok, o, e.E, ((SetType)eeType).Arg);
- Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, o));
+ Bpl.Expr oNotFresh = Old.IsAlloced(expr.tok, o);
+ Bpl.Expr oIsFresh = Bpl.Expr.Not(oNotFresh);
Bpl.Expr body = Bpl.Expr.Imp(Bpl.Expr.And(oNotNull, oInSet), oIsFresh);
- return new Bpl.ForallExpr(expr.tok, new List<Variable> { oVar }, body);
+ // TRIGGERS: Does this make sense? VSI-Benchmarks\b7
+ // TRIG (forall $o: ref :: $o != null && read($Heap, this, _module.List.Repr)[$Box($o)] && $o != this ==> !read(old($Heap), $o, alloc))
+ // TRIG (forall $o: ref :: $o != null && read($Heap, this, _module.Stream.footprint)[$Box($o)] && $o != this ==> !read(old($Heap), $o, alloc))
+ var trigger = BplTrigger(oNotFresh); // NEW_TRIGGER
+ return new Bpl.ForallExpr(expr.tok, new List<Variable> { oVar }, trigger, body);
} else if (eeType is SeqType) {
// generate: (forall $i: int :: 0 <= $i && $i < Seq#Length(X) && Unbox(Seq#Index(X,$i)) != null ==> !old($Heap)[Unbox(Seq#Index(X,$i)),alloc])
- // TODO: trigger?
Bpl.Variable iVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, "$i", Bpl.Type.Int));
Bpl.Expr i = new Bpl.IdentifierExpr(expr.tok, iVar);
- Bpl.Expr iBounds = translator.InSeqRange(expr.tok, i, TrExpr(e.E), true, null, false);
- Bpl.Expr XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.RefType, TrExpr(e.E), i);
+ Bpl.Expr iBounds = translator.InSeqRange(expr.tok, i, TrExpr(e.E, initEtran, funcEtran, existEtran), true, null, false);
+ Bpl.Expr XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.RefType, TrExpr(e.E, initEtran, funcEtran, existEtran), i);
XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, predef.RefType, XsubI);
- Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, XsubI));
+ Bpl.Expr oNotFresh = Old.IsAlloced(expr.tok, XsubI);
+ Bpl.Expr oIsFresh = Bpl.Expr.Not(oNotFresh);
Bpl.Expr xsubiNotNull = Bpl.Expr.Neq(XsubI, predef.Null);
Bpl.Expr body = Bpl.Expr.Imp(Bpl.Expr.And(iBounds, xsubiNotNull), oIsFresh);
+ //TRIGGERS: Does this make sense? dafny0\SmallTests
+ // BROKEN // NEW_TRIGGER
+ //TRIG (forall $i: int :: 0 <= $i && $i < Seq#Length(Q#0) && $Unbox(Seq#Index(Q#0, $i)): ref != null ==> !read(old($Heap), $Unbox(Seq#Index(Q#0, $i)): ref, alloc))
return new Bpl.ForallExpr(expr.tok, new List<Variable> { iVar }, body);
} else if (eeType.IsDatatype) {
// translator.FunctionCall(e.tok, BuiltinFunction.DtAlloc, null, TrExpr(e.E), Old.HeapExpr);
- Bpl.Expr alloc = translator.MkIsAlloc(TrExpr(e.E), eeType, Old.HeapExpr);
+ Bpl.Expr alloc = translator.MkIsAlloc(TrExpr(e.E, initEtran, funcEtran, existEtran), eeType, Old.HeapExpr);
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, alloc);
} else {
// generate: x != null && !old($Heap)[x]
- Bpl.Expr oNull = Bpl.Expr.Neq(TrExpr(e.E), predef.Null);
- Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, TrExpr(e.E)));
+ Bpl.Expr oNull = Bpl.Expr.Neq(TrExpr(e.E, initEtran, funcEtran, existEtran), predef.Null);
+ Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, TrExpr(e.E, initEtran, funcEtran, existEtran)));
return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And, oNull, oIsFresh);
}
default:
@@ -10826,14 +11367,14 @@ namespace Microsoft.Dafny {
ct = BuiltinFunction.RealToInt;
} else {
Contract.Assert(fromInt == toInt);
- return TrExpr(e.E);
+ return TrExpr(e.E, initEtran, funcEtran, existEtran);
}
- return translator.FunctionCall(e.tok, ct, null, TrExpr(e.E));
+ return translator.FunctionCall(e.tok, ct, null, TrExpr(e.E, initEtran, funcEtran, existEtran));
} else if (expr is BinaryExpr) {
BinaryExpr e = (BinaryExpr)expr;
bool isReal = e.E0.Type.IsNumericBased(Type.NumericPersuation.Real);
- Bpl.Expr e0 = TrExpr(e.E0);
+ Bpl.Expr e0 = TrExpr(e.E0, initEtran, funcEtran, existEtran);
if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InSet) {
return TrInSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInSet translate e.E1
} else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSet) {
@@ -10845,7 +11386,7 @@ namespace Microsoft.Dafny {
Bpl.Expr arg = TrInMultiSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInMultiSet translate e.E1
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);
}
- Bpl.Expr e1 = TrExpr(e.E1);
+ Bpl.Expr e1 = TrExpr(e.E1, initEtran, funcEtran, existEtran);
BinaryOperator.Opcode bOpcode;
Bpl.Type typ;
var oe0 = e0;
@@ -10882,7 +11423,7 @@ namespace Microsoft.Dafny {
if (cot != null) {
var e0args = e.E0.Type.NormalizeExpand().TypeArgs;
var e1args = e.E1.Type.NormalizeExpand().TypeArgs;
- return translator.CoEqualCall(cot, e0args, e1args, null, LayerN(2), e0, e1, expr.tok);
+ return translator.CoEqualCall(cot, e0args, e1args, null, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e0, e1, expr.tok);
}
typ = Bpl.Type.Bool;
bOpcode = BinaryOperator.Opcode.Eq; break;
@@ -10891,7 +11432,7 @@ namespace Microsoft.Dafny {
if (cotx != null) {
var e0args = e.E0.Type.NormalizeExpand().TypeArgs;
var e1args = e.E1.Type.NormalizeExpand().TypeArgs;
- var x = translator.CoEqualCall(cotx, e0args, e1args, null, LayerN(2), e0, e1, expr.tok);
+ var x = translator.CoEqualCall(cotx, e0args, e1args, null, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e0, e1, expr.tok);
return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, x);
}
typ = Bpl.Type.Bool;
@@ -10902,7 +11443,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Lt;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_lt_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_lt_boogie", Bpl.Type.Bool, e0, e1, liftLit);
}
case BinaryExpr.ResolvedOpcode.Le:
@@ -10912,7 +11453,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Le;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_le_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_le_boogie", Bpl.Type.Bool, e0, e1, false);
}
case BinaryExpr.ResolvedOpcode.Ge:
keepLits = true;
@@ -10921,7 +11462,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Ge;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_ge_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_ge_boogie", Bpl.Type.Bool, e0, e1, false);
}
case BinaryExpr.ResolvedOpcode.Gt:
if (isReal || !DafnyOptions.O.DisableNLarith) {
@@ -10929,7 +11470,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Gt;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_gt_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_gt_boogie", Bpl.Type.Bool, e0, e1, liftLit);
}
case BinaryExpr.ResolvedOpcode.Add:
if (!DafnyOptions.O.DisableNLarith) {
@@ -10941,7 +11482,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Add;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_add_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_add_boogie", Bpl.Type.Int, e0, e1, liftLit);
}
}
case BinaryExpr.ResolvedOpcode.Sub:
@@ -10954,7 +11495,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Sub;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_sub_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_sub_boogie", Bpl.Type.Int, e0, e1, liftLit);
}
}
case BinaryExpr.ResolvedOpcode.Mul:
@@ -10967,7 +11508,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Mul;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_mul_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_mul_boogie", Bpl.Type.Int, e0, e1, liftLit);
}
}
@@ -10980,7 +11521,7 @@ namespace Microsoft.Dafny {
typ = Bpl.Type.Int;
bOpcode = BinaryOperator.Opcode.Div; break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_div_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_div_boogie", Bpl.Type.Int, e0, e1, liftLit);
}
}
case BinaryExpr.ResolvedOpcode.Mod:
@@ -10993,7 +11534,7 @@ namespace Microsoft.Dafny {
bOpcode = BinaryOperator.Opcode.Mod;
break;
} else {
- return translator.FunctionCall(expr.tok, "INTERNAL_mod_boogie", Bpl.Type.Int, e0, e1);
+ return TrToFunctionCall(expr.tok, "INTERNAL_mod_boogie", Bpl.Type.Int, e0, e1, liftLit);
}
}
@@ -11017,31 +11558,55 @@ namespace Microsoft.Dafny {
return Bpl.Expr.Binary(expr.tok, bOp, operand0, operand1);
}
- case BinaryExpr.ResolvedOpcode.SetEq:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetEqual, null, e0, e1);
- case BinaryExpr.ResolvedOpcode.SetNeq:
- return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, translator.FunctionCall(expr.tok, BuiltinFunction.SetEqual, null, e0, e1));
- case BinaryExpr.ResolvedOpcode.ProperSubset:
+ case BinaryExpr.ResolvedOpcode.SetEq: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetEqual : BuiltinFunction.ISetEqual;
+ return translator.FunctionCall(expr.tok, f, null, e0, e1);
+ }
+ case BinaryExpr.ResolvedOpcode.SetNeq: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetEqual : BuiltinFunction.ISetEqual;
+ return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, translator.FunctionCall(expr.tok, f, null, e0, e1));
+ }
+ case BinaryExpr.ResolvedOpcode.ProperSubset: {
return translator.ProperSubset(expr.tok, e0, e1);
- case BinaryExpr.ResolvedOpcode.Subset:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetSubset, null, e0, e1);
- case BinaryExpr.ResolvedOpcode.Superset:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetSubset, null, e1, e0);
+ }
+ case BinaryExpr.ResolvedOpcode.Subset: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetSubset : BuiltinFunction.ISetSubset;
+ return translator.FunctionCall(expr.tok, f, null, e0, e1);
+ }
+ case BinaryExpr.ResolvedOpcode.Superset: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetSubset : BuiltinFunction.ISetSubset;
+ return translator.FunctionCall(expr.tok, f, null, e1, e0);
+ }
case BinaryExpr.ResolvedOpcode.ProperSuperset:
return translator.ProperSubset(expr.tok, e1, e0);
- case BinaryExpr.ResolvedOpcode.Disjoint:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetDisjoint, null, e0, e1);
+ case BinaryExpr.ResolvedOpcode.Disjoint: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetDisjoint : BuiltinFunction.ISetDisjoint;
+ return translator.FunctionCall(expr.tok, f, null, e0, e1);
+ }
case BinaryExpr.ResolvedOpcode.InSet:
Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
case BinaryExpr.ResolvedOpcode.NotInSet:
Contract.Assert(false); throw new cce.UnreachableException(); // this case handled above
- case BinaryExpr.ResolvedOpcode.Union:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetUnion, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
- case BinaryExpr.ResolvedOpcode.Intersection:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetIntersection, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
- case BinaryExpr.ResolvedOpcode.SetDifference:
- return translator.FunctionCall(expr.tok, BuiltinFunction.SetDifference, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
-
+ case BinaryExpr.ResolvedOpcode.Union: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetUnion : BuiltinFunction.ISetUnion;
+ return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
+ }
+ case BinaryExpr.ResolvedOpcode.Intersection: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetIntersection : BuiltinFunction.ISetIntersection;
+ return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
+ }
+ case BinaryExpr.ResolvedOpcode.SetDifference: {
+ bool finite = e.E1.Type.AsSetType.Finite;
+ var f = finite ? BuiltinFunction.SetDifference : BuiltinFunction.ISetDifference;
+ return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);
+ }
case BinaryExpr.ResolvedOpcode.MultiSetEq:
return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEqual, null, e0, e1);
case BinaryExpr.ResolvedOpcode.MultiSetNeq:
@@ -11133,14 +11698,14 @@ namespace Microsoft.Dafny {
var ae1 = keepLits ? oe1 : e1;
Bpl.Expr re = Bpl.Expr.Binary(expr.tok, bOpcode, ae0, ae1);
if (liftLit) {
- re = translator.Lit(re, typ);
+ re = MaybeLit(re, typ);
}
return re;
} else if (expr is TernaryExpr) {
var e = (TernaryExpr)expr;
- var e0 = TrExpr(e.E0);
- var e1 = TrExpr(e.E1);
- var e2 = TrExpr(e.E2);
+ var e0 = TrExpr(e.E0, initEtran, funcEtran, existEtran);
+ var e1 = TrExpr(e.E1, initEtran, funcEtran, existEtran);
+ var e2 = TrExpr(e.E2, initEtran, funcEtran, existEtran);
switch (e.Op) {
case TernaryExpr.Opcode.PrefixEqOp:
case TernaryExpr.Opcode.PrefixNeqOp:
@@ -11148,7 +11713,7 @@ namespace Microsoft.Dafny {
var e2type = e.E2.Type.NormalizeExpand();
var cot = e1type.AsCoDatatype;
Contract.Assert(cot != null); // the argument types of prefix equality (and prefix disequality) are codatatypes
- var r = translator.CoEqualCall(cot, e1type.TypeArgs, e2type.TypeArgs, e0, LayerN(2), e1, e2);
+ var r = translator.CoEqualCall(cot, e1type.TypeArgs, e2type.TypeArgs, e0, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e1, e2);
if (e.Op == TernaryExpr.Opcode.PrefixEqOp) {
return r;
} else {
@@ -11160,65 +11725,70 @@ namespace Microsoft.Dafny {
} else if (expr is LetExpr) {
var e = (LetExpr)expr;
if (e.Exact) {
- return TrExpr(GetSubstitutedBody(e));
+ return TrExpr(GetSubstitutedBody(e), initEtran, funcEtran, existEtran);
} else {
var d = translator.LetDesugaring(e);
- return TrExpr(d);
+ return TrExpr(d, initEtran, funcEtran, existEtran);
}
} else if (expr is NamedExpr) {
- return TrExpr(((NamedExpr)expr).Body);
+ return TrExpr(((NamedExpr)expr).Body, initEtran, funcEtran, existEtran);
} else if (expr is QuantifierExpr) {
QuantifierExpr e = (QuantifierExpr)expr;
- List<Variable> tyvars = translator.MkTyParamBinders(e.TypeArgs);
- List<Variable> bvars = new List<Variable>();
- var initEtran = this;
- var bodyEtran = this;
- bool _scratch = true;
+ if (e.SplitQuantifier != null) {
+ return TrExpr(e.SplitQuantifierExpression, initEtran, existEtran, existEtran);
+ } else {
+ List<Variable> tyvars = translator.MkTyParamBinders(e.TypeArgs);
+ List<Variable> bvars = new List<Variable>();
- Bpl.Expr antecedent = Bpl.Expr.True;
+ var etran = initEtran ?? this;
+ var bodyEtran = this;
+ existEtran = e is ForallExpr ? this : existEtran;
+ bool _scratch = true;
- if (Attributes.ContainsBool(e.Attributes, "layerQuantifier", ref _scratch)) {
- // If this is a layer quantifier, quantify over layers here, and use $LS(ly) layers in the translation of the body
- var ly = BplBoundVar(e.Refresh("q$ly#", translator.CurrentIdGenerator), predef.LayerType, bvars);
- Expr layer = translator.LayerSucc(ly);
- bodyEtran = new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layer, layer, modifiesFrame);
- }
- if (Attributes.ContainsBool(e.Attributes, "heapQuantifier", ref _scratch)) {
- var h = BplBoundVar(e.Refresh("q$heap#", translator.CurrentIdGenerator), predef.HeapType, bvars);
- bodyEtran = new ExpressionTranslator(bodyEtran, h);
- antecedent = BplAnd(new List<Bpl.Expr> {
+ Bpl.Expr antecedent = Bpl.Expr.True;
+
+ if (Attributes.ContainsBool(e.Attributes, "layerQuantifier", ref _scratch)) {
+ // If this is a layer quantifier, quantify over layers here, and use $LS(ly) layers in the translation of the body
+ var ly = BplBoundVar(e.Refresh("q$ly#", translator.CurrentIdGenerator), predef.LayerType, bvars);
+ bodyEtran = new ExpressionTranslator(translator, predef, HeapExpr, This, applyLimited_CurrentFunction, new FuelSetting(translator, 1, ly), new FuelSetting(translator, 1, ly), modifiesFrame, stripLits);
+ }
+ if (Attributes.ContainsBool(e.Attributes, "heapQuantifier", ref _scratch)) {
+ var h = BplBoundVar(e.Refresh("q$heap#", translator.CurrentIdGenerator), predef.HeapType, bvars);
+ bodyEtran = new ExpressionTranslator(bodyEtran, h);
+ antecedent = BplAnd(new List<Bpl.Expr> {
antecedent,
translator.FunctionCall(e.tok, BuiltinFunction.IsGoodHeap, null, h),
- translator.HeapSameOrSucc(initEtran.HeapExpr, h)
+ translator.HeapSameOrSucc(etran.HeapExpr, h)
});
- }
+ }
- antecedent = BplAnd(antecedent, bodyEtran.TrBoundVariables(e.BoundVars, bvars));
+ antecedent = BplAnd(antecedent, etran.TrBoundVariables(e.BoundVars, bvars));
- Bpl.QKeyValue kv = TrAttributes(e.Attributes, "trigger");
- Bpl.Trigger tr = null;
- for (Attributes aa = e.Attributes; aa != null; aa = aa.Prev) {
- if (aa.Name == "trigger") {
- List<Bpl.Expr> tt = new List<Bpl.Expr>();
- foreach (var arg in aa.Args) {
- tt.Add(bodyEtran.TrExpr(arg));
+ Bpl.QKeyValue kv = TrAttributes(e.Attributes, "trigger");
+ Bpl.Trigger tr = null;
+ var argsEtran = bodyEtran.WithNoLits();
+ foreach (var aa in e.Attributes.AsEnumerable()) {
+ if (aa.Name == "trigger") {
+ List<Bpl.Expr> tt = new List<Bpl.Expr>();
+ foreach (var arg in aa.Args) {
+ tt.Add(argsEtran.TrExpr(arg, initEtran, existEtran, existEtran));
+ }
+ tr = new Bpl.Trigger(expr.tok, true, tt, tr);
}
- tr = new Bpl.Trigger(expr.tok, true, tt, tr);
}
- }
- if (e.Range != null) {
- antecedent = BplAnd(antecedent, bodyEtran.TrExpr(e.Range));
- }
- Bpl.Expr body = bodyEtran.TrExpr(e.Term);
+ if (e.Range != null) {
+ antecedent = BplAnd(antecedent, etran.TrExpr(e.Range, initEtran, existEtran, existEtran));
+ }
+ Bpl.Expr body = bodyEtran.TrExpr(e.Term, initEtran, existEtran, existEtran);
- if (e is ForallExpr) {
- return new Bpl.ForallExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars,bvars), kv, tr, Bpl.Expr.Imp(antecedent, body));
- } else {
- Contract.Assert(e is ExistsExpr);
- return new Bpl.ExistsExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars,bvars), kv, tr, Bpl.Expr.And(antecedent, body));
+ if (e is ForallExpr) {
+ return new Bpl.ForallExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars, bvars), kv, tr, Bpl.Expr.Imp(antecedent, body));
+ } else {
+ Contract.Assert(e is ExistsExpr);
+ return new Bpl.ExistsExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars, bvars), kv, tr, Bpl.Expr.And(antecedent, body));
+ }
}
-
} else if (expr is SetComprehension) {
var e = (SetComprehension)expr;
// Translate "set xs | R :: T" into "lambda y: BoxType :: (exists xs :: CorrectType(xs) && R && y==Box(T))".
@@ -11229,8 +11799,8 @@ namespace Microsoft.Dafny {
var yVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, translator.CurrentIdGenerator.FreshId("$y#"), predef.BoxType));
Bpl.Expr y = new Bpl.IdentifierExpr(expr.tok, yVar);
- var eq = Bpl.Expr.Eq(y, BoxIfNecessary(expr.tok, TrExpr(e.Term), e.Term.Type));
- var ebody = Bpl.Expr.And(BplAnd(typeAntecedent, TrExpr(e.Range)), eq);
+ var eq = Bpl.Expr.Eq(y, BoxIfNecessary(expr.tok, TrExpr(e.Term, initEtran, funcEtran, existEtran), e.Term.Type));
+ var ebody = Bpl.Expr.And(BplAnd(typeAntecedent, TrExpr(e.Range, initEtran, funcEtran, existEtran)), eq);
var triggers = translator.TrTrigger(this, e.Attributes, e.tok);
var exst = new Bpl.ExistsExpr(expr.tok, bvars, triggers, ebody);
@@ -11257,9 +11827,9 @@ namespace Microsoft.Dafny {
Dictionary<IVariable, Expression> subst = new Dictionary<IVariable,Expression>();
subst.Add(e.BoundVars[0], new BoogieWrapper(unboxy,e.BoundVars[0].Type));
- var ebody = BplAnd(typeAntecedent ?? Bpl.Expr.True, TrExpr(translator.Substitute(e.Range, null, subst)));
+ var ebody = BplAnd(typeAntecedent ?? Bpl.Expr.True, TrExpr(translator.Substitute(e.Range, null, subst), initEtran, funcEtran, existEtran));
Bpl.Expr l1 = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { yVar }, kv, ebody);
- ebody = TrExpr(translator.Substitute(e.Term, null, subst));
+ ebody = TrExpr(translator.Substitute(e.Term, null, subst), initEtran, funcEtran, existEtran);
Bpl.Expr l2 = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { yVar }, kv, BoxIfNecessary(expr.tok, ebody, e.Term.Type));
bool finite = e.Finite;
@@ -11268,41 +11838,49 @@ namespace Microsoft.Dafny {
} else if (expr is LambdaExpr) {
var e = (LambdaExpr)expr;
-
return TrLambdaExpr(e);
+
} else if (expr is StmtExpr) {
var e = (StmtExpr)expr;
- return TrExpr(e.E);
+ return TrExpr(e.E, initEtran, funcEtran, existEtran);
} else if (expr is ITEExpr) {
ITEExpr e = (ITEExpr)expr;
- var g = translator.RemoveLit(TrExpr(e.Test));
- var thn = translator.RemoveLit(TrExpr(e.Thn));
- var els = translator.RemoveLit(TrExpr(e.Els));
+ var g = translator.RemoveLit(TrExpr(e.Test, initEtran, funcEtran, existEtran));
+ var thn = translator.RemoveLit(TrExpr(e.Thn, initEtran, funcEtran, existEtran));
+ var els = translator.RemoveLit(TrExpr(e.Els, initEtran, funcEtran, existEtran));
return new NAryExpr(expr.tok, new IfThenElse(expr.tok), new List<Bpl.Expr> { g, thn, els });
} else if (expr is MatchExpr) {
var e = (MatchExpr)expr;
var ite = DesugarMatchExpr(e);
- return TrExpr(ite);
+ return TrExpr(ite, initEtran, funcEtran, existEtran);
} else if (expr is ConcreteSyntaxExpression) {
var e = (ConcreteSyntaxExpression)expr;
- return TrExpr(e.ResolvedExpression);
+ return TrExpr(e.ResolvedExpression, initEtran, funcEtran, existEtran);
} else if (expr is BoxingCastExpr) {
BoxingCastExpr e = (BoxingCastExpr)expr;
- return translator.CondApplyBox(e.tok, TrExpr(e.E), e.FromType, e.ToType);
+ return translator.CondApplyBox(e.tok, TrExpr(e.E, initEtran, funcEtran, existEtran), e.FromType, e.ToType);
} else if (expr is UnboxingCastExpr) {
UnboxingCastExpr e = (UnboxingCastExpr)expr;
- return translator.CondApplyUnbox(e.tok, TrExpr(e.E), e.FromType, e.ToType);
+ return translator.CondApplyUnbox(e.tok, TrExpr(e.E, initEtran, funcEtran, existEtran), e.FromType, e.ToType);
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
}
}
+ private Expr TrToFunctionCall(IToken tok, string function, Bpl.Type returnType, Bpl.Expr e0, Bpl.Expr e1, bool liftLit) {
+ Bpl.Expr re = translator.FunctionCall(tok, function, returnType, e0, e1);
+ if (liftLit) {
+ re = MaybeLit(re, returnType);
+ }
+ return re;
+ }
+
private Expr TrLambdaExpr(LambdaExpr e) {
var bvars = new List<Bpl.Variable>();
var bargs = new List<Bpl.Expr>();
@@ -11340,22 +11918,19 @@ namespace Microsoft.Dafny {
}
var rdvars = new List<Bpl.Variable>();
- var o = translator.UnboxIfBoxed(BplBoundVar(varNameGen.FreshId("#o#"), predef.BoxType, rdvars), new ObjectType());
-
- Bpl.Expr ante = Bpl.Expr.And(Bpl.Expr.Neq(o, predef.Null), et.IsAlloced(e.tok, o));
- Bpl.Expr consequent = translator.InRWClause(e.tok, o, null, e.Reads.ConvertAll(su.SubstFrameExpr), et, null, null);
- Bpl.Expr rdbody =
- new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), rdvars, null,
- BplImp(ante, consequent));
+ var o = BplBoundVar(varNameGen.FreshId("#o#"), predef.RefType, rdvars);
+ Bpl.Expr rdbody = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), rdvars, null,
+ translator.InRWClause(e.tok, o, null, e.Reads.ConvertAll(su.SubstFrameExpr), et, null, null));
+ rdbody = translator.FunctionCall(e.tok, "SetRef_to_SetBox", predef.SetType(e.tok, true, predef.BoxType), rdbody);
- return translator.Lit(
+ return MaybeLit(
translator.FunctionCall(e.tok, BuiltinFunction.AtLayer, predef.HandleType,
new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), lvars, null,
translator.FunctionCall(e.tok, translator.Handle(e.BoundVars.Count), predef.BoxType,
new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, ebody),
new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, reqbody),
new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, rdbody))),
- layerIntraCluster ?? layerInterCluster),
+ layerIntraCluster != null ? layerIntraCluster.ToExpr() : layerInterCluster.ToExpr()),
predef.HandleType);
}
@@ -11433,6 +12008,20 @@ namespace Microsoft.Dafny {
return typeAntecedent;
}
+ public List<Tuple<Bpl.Variable, Bpl.Expr>> TrBoundVariables_SeparateWhereClauses(List<BoundVar/*!*/> boundVars) {
+ Contract.Requires(boundVars != null);
+ Contract.Ensures(Contract.Result<List<Tuple<Bpl.Variable, Bpl.Expr>>>() != null);
+
+ var varsAndAntecedents = new List<Tuple<Bpl.Variable, Bpl.Expr>>();
+ foreach (BoundVar bv in boundVars) {
+ var tid = new Bpl.TypedIdent(bv.tok, bv.AssignUniqueName(translator.currentDeclaration.IdGenerator), translator.TrType(bv.Type));
+ var bvar = new Bpl.BoundVariable(bv.tok, tid);
+ var wh = translator.GetWhereClause(bv.tok, new Bpl.IdentifierExpr(bv.tok, bvar), bv.Type, this);
+ varsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(bvar, wh));
+ }
+ return varsAndAntecedents;
+ }
+
public Bpl.Expr TrBoundVariablesRename(List<BoundVar> boundVars, List<Variable> bvars, out Dictionary<IVariable, Expression> substMap) {
Contract.Requires(boundVars != null);
Contract.Requires(bvars != null);
@@ -11456,11 +12045,11 @@ namespace Microsoft.Dafny {
}
public List<Expr> FunctionInvocationArguments(FunctionCallExpr e, Bpl.Expr layerArgument) {
- bool returnLit;
- return FunctionInvocationArguments(e, layerArgument, out returnLit);
+ bool dummy;
+ return FunctionInvocationArguments(e, layerArgument, out dummy);
}
- public List<Expr> FunctionInvocationArguments(FunctionCallExpr e, Bpl.Expr layerArgument, out bool returnLit) {
+ public List<Expr> FunctionInvocationArguments(FunctionCallExpr e, Bpl.Expr layerArgument, out bool argsAreLit) {
Contract.Requires(e != null);
Contract.Ensures(Contract.Result<List<Bpl.Expr>>() != null);
@@ -11479,12 +12068,12 @@ namespace Microsoft.Dafny {
if (!e.Function.IsStatic) {
args.Add(TrExpr(e.Receiver));
}
- returnLit = true;
+ argsAreLit = true;
for (int i = 0; i < e.Args.Count; i++) {
Expression ee = e.Args[i];
Type t = e.Function.Formals[i].Type;
Expr tr_ee = TrExpr(ee);
- returnLit = returnLit && translator.IsLit(tr_ee);
+ argsAreLit = argsAreLit && translator.IsLit(tr_ee);
args.Add(translator.CondApplyBox(e.tok, tr_ee, cce.NonNull(ee.Type), t));
}
return args;
@@ -11640,13 +12229,13 @@ namespace Microsoft.Dafny {
public Bpl.QKeyValue TrAttributes(Attributes attrs, string skipThisAttribute) {
Bpl.QKeyValue kv = null;
- for ( ; attrs != null; attrs = attrs.Prev) {
- if (attrs.Name == skipThisAttribute
- || attrs.Name == "axiom") { // Dafny's axiom attribute clashes with Boogie's axiom keyword
+ foreach (var attr in attrs.AsEnumerable()) {
+ if (attr.Name == skipThisAttribute
+ || attr.Name == "axiom") { // Dafny's axiom attribute clashes with Boogie's axiom keyword
continue;
}
List<object> parms = new List<object>();
- foreach (var arg in attrs.Args) {
+ foreach (var arg in attr.Args) {
var s = arg.AsStringLiteral();
if (s != null) {
// pass string literals down to Boogie as string literals, not as their expression translation
@@ -11657,7 +12246,7 @@ namespace Microsoft.Dafny {
parms.Add(e);
}
}
- kv = new Bpl.QKeyValue(Token.NoToken, attrs.Name, parms, kv);
+ kv = new Bpl.QKeyValue(Token.NoToken, attr.Name, parms, kv);
}
return kv;
}
@@ -11718,6 +12307,15 @@ namespace Microsoft.Dafny {
SetSubset,
SetDisjoint,
+ ISetEmpty,
+ ISetUnionOne,
+ ISetUnion,
+ ISetIntersection,
+ ISetDifference,
+ ISetEqual,
+ ISetSubset,
+ ISetDisjoint,
+
MultiSetCard,
MultiSetEmpty,
MultiSetUnionOne,
@@ -11771,6 +12369,7 @@ namespace Microsoft.Dafny {
IntToReal,
IsGoodHeap,
+ IsHeapAnchor,
HeapSucc,
HeapSuccGhost,
@@ -11897,25 +12496,25 @@ namespace Microsoft.Dafny {
case BuiltinFunction.SetEmpty: {
Contract.Assert(args.Length == 0);
Contract.Assert(typeInstantiation != null);
- Bpl.Type resultType = predef.SetType(tok, typeInstantiation);
+ Bpl.Type resultType = predef.SetType(tok, true, typeInstantiation);
return Bpl.Expr.CoerceType(tok, FunctionCall(tok, "Set#Empty", resultType, args), resultType);
}
case BuiltinFunction.SetUnionOne:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation != null);
- return FunctionCall(tok, "Set#UnionOne", predef.SetType(tok, typeInstantiation), args);
+ return FunctionCall(tok, "Set#UnionOne", predef.SetType(tok, true, typeInstantiation), args);
case BuiltinFunction.SetUnion:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation != null);
- return FunctionCall(tok, "Set#Union", predef.SetType(tok, typeInstantiation), args);
+ return FunctionCall(tok, "Set#Union", predef.SetType(tok, true, typeInstantiation), args);
case BuiltinFunction.SetIntersection:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation != null);
- return FunctionCall(tok, "Set#Intersection", predef.SetType(tok, typeInstantiation), args);
+ return FunctionCall(tok, "Set#Intersection", predef.SetType(tok, true, typeInstantiation), args);
case BuiltinFunction.SetDifference:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation != null);
- return FunctionCall(tok, "Set#Difference", predef.SetType(tok, typeInstantiation), args);
+ return FunctionCall(tok, "Set#Difference", predef.SetType(tok, true, typeInstantiation), args);
case BuiltinFunction.SetEqual:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation == null);
@@ -11928,7 +12527,40 @@ namespace Microsoft.Dafny {
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation == null);
return FunctionCall(tok, "Set#Disjoint", Bpl.Type.Bool, args);
-
+ case BuiltinFunction.ISetEmpty: {
+ Contract.Assert(args.Length == 0);
+ Contract.Assert(typeInstantiation != null);
+ Bpl.Type resultType = predef.SetType(tok, false, typeInstantiation);
+ return Bpl.Expr.CoerceType(tok, FunctionCall(tok, "ISet#Empty", resultType, args), resultType);
+ }
+ case BuiltinFunction.ISetUnionOne:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "ISet#UnionOne", predef.SetType(tok, false, typeInstantiation), args);
+ case BuiltinFunction.ISetUnion:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "ISet#Union", predef.SetType(tok, false, typeInstantiation), args);
+ case BuiltinFunction.ISetIntersection:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "ISet#Intersection", predef.SetType(tok, false, typeInstantiation), args);
+ case BuiltinFunction.ISetDifference:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation != null);
+ return FunctionCall(tok, "ISet#Difference", predef.SetType(tok, false, typeInstantiation), args);
+ case BuiltinFunction.ISetEqual:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "ISet#Equal", Bpl.Type.Bool, args);
+ case BuiltinFunction.ISetSubset:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "ISet#Subset", Bpl.Type.Bool, args);
+ case BuiltinFunction.ISetDisjoint:
+ Contract.Assert(args.Length == 2);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "ISet#Disjoint", Bpl.Type.Bool, args);
case BuiltinFunction.MultiSetCard:
Contract.Assert(args.Length == 1);
Contract.Assert(typeInstantiation == null);
@@ -12118,6 +12750,10 @@ namespace Microsoft.Dafny {
Contract.Assert(args.Length == 1);
Contract.Assert(typeInstantiation == null);
return FunctionCall(tok, "$IsGoodHeap", Bpl.Type.Bool, args);
+ case BuiltinFunction.IsHeapAnchor:
+ Contract.Assert(args.Length == 1);
+ Contract.Assert(typeInstantiation == null);
+ return FunctionCall(tok, "$IsHeapAnchor", Bpl.Type.Bool, args);
case BuiltinFunction.HeapSucc:
Contract.Assert(args.Length == 2);
Contract.Assert(typeInstantiation == null);
@@ -12271,36 +12907,39 @@ namespace Microsoft.Dafny {
Contract.Ensures(Contract.Result<List<SplitExprInfo>>() != null);
var splits = new List<SplitExprInfo>();
- splitHappened = TrSplitExpr(expr, splits, true, int.MaxValue, apply_induction, etran);
+ splitHappened = TrSplitExpr(expr, splits, true, int.MaxValue, true, apply_induction, etran);
return splits;
}
- List<SplitExprInfo/*!*/>/*!*/ TrSplitExpr(Expression expr, ExpressionTranslator etran, int heightLimit, bool apply_induction, out bool splitHappened)
+ List<SplitExprInfo> TrSplitExprForMethodSpec(Expression expr, ExpressionTranslator etran, MethodTranslationKind kind)
{
Contract.Requires(expr != null);
Contract.Requires(etran != null);
Contract.Ensures(Contract.Result<List<SplitExprInfo>>() != null);
var splits = new List<SplitExprInfo>();
- splitHappened = TrSplitExpr(expr, splits, true, heightLimit, apply_induction, etran);
+ var apply_induction = true;/*kind == MethodTranslationKind.Implementation*/;
+ bool splitHappened; // we don't actually care
+ splitHappened = TrSplitExpr(expr, splits, true, int.MaxValue, kind != MethodTranslationKind.InterModuleCall, apply_induction, etran);
return splits;
}
Bpl.Trigger TrTrigger(ExpressionTranslator etran, Attributes attribs, IToken tok, Dictionary<IVariable, Expression> substMap = null)
{
+ Contract.Requires(etran != null);
+ Contract.Requires(tok != null);
+ var argsEtran = etran.WithNoLits();
Bpl.Trigger tr = null;
- for (Attributes aa = attribs; aa != null; aa = aa.Prev) {
- if (aa.Name == "trigger") {
- List<Bpl.Expr> tt = new List<Bpl.Expr>();
- foreach (var arg in aa.Args) {
- if (substMap == null) {
- tt.Add(etran.TrExpr(arg));
- } else {
- tt.Add(etran.TrExpr(Substitute(arg, null, substMap)));
- }
+ foreach (var trigger in attribs.AsEnumerable().Where(aa => aa.Name == "trigger").Select(aa => aa.Args)) {
+ List<Bpl.Expr> tt = new List<Bpl.Expr>();
+ foreach (var arg in trigger) {
+ if (substMap == null) {
+ tt.Add(argsEtran.TrExpr(arg));
+ } else {
+ tt.Add(argsEtran.TrExpr(Substitute(arg, null, substMap)));
}
- tr = new Bpl.Trigger(tok, true, tt, tr);
}
+ tr = new Bpl.Trigger(tok, true, tt, tr);
}
return tr;
}
@@ -12311,7 +12950,7 @@ namespace Microsoft.Dafny {
/// if its body is available in the current context and its height is less than "heightLimit" (if "heightLimit" is
/// passed in as 0, then no functions will be inlined).
/// </summary>
- bool TrSplitExpr(Expression expr, List<SplitExprInfo/*!*/>/*!*/ splits, bool position, int heightLimit, bool apply_induction, ExpressionTranslator etran) {
+ bool TrSplitExpr(Expression expr, List<SplitExprInfo/*!*/>/*!*/ splits, bool position, int heightLimit, bool inlineProtectedFunctions, bool apply_induction, ExpressionTranslator etran) {
Contract.Requires(expr != null);
Contract.Requires(expr.Type.IsBoolType || (expr is BoxingCastExpr && ((BoxingCastExpr)expr).E.Type.IsBoolType));
Contract.Requires(splits != null);
@@ -12320,7 +12959,7 @@ namespace Microsoft.Dafny {
if (expr is BoxingCastExpr) {
var bce = (BoxingCastExpr)expr;
var ss = new List<SplitExprInfo>();
- if (TrSplitExpr(bce.E, ss, position, heightLimit, apply_induction, etran)) {
+ if (TrSplitExpr(bce.E, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran)) {
foreach (var s in ss) {
splits.Add(new SplitExprInfo(s.Kind, CondApplyBox(s.E.tok, s.E, bce.FromType, bce.ToType)));
}
@@ -12329,22 +12968,22 @@ namespace Microsoft.Dafny {
} else if (expr is ConcreteSyntaxExpression) {
var e = (ConcreteSyntaxExpression)expr;
- return TrSplitExpr(e.ResolvedExpression, splits, position, heightLimit, apply_induction, etran);
+ return TrSplitExpr(e.ResolvedExpression, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
} else if (expr is LetExpr) {
var e = (LetExpr)expr;
if (e.Exact) {
- return TrSplitExpr(etran.GetSubstitutedBody(e), splits, position, heightLimit, apply_induction, etran);
+ return TrSplitExpr(etran.GetSubstitutedBody(e), splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
} else {
var d = LetDesugaring(e);
- return TrSplitExpr(d, splits, position, heightLimit, apply_induction, etran);
+ return TrSplitExpr(d, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
}
} else if (expr is UnaryOpExpr) {
var e = (UnaryOpExpr)expr;
if (e.Op == UnaryOpExpr.Opcode.Not) {
var ss = new List<SplitExprInfo>();
- if (TrSplitExpr(e.E, ss, !position, heightLimit, apply_induction, etran)) {
+ if (TrSplitExpr(e.E, ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran)) {
foreach (var s in ss) {
splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Unary(s.E.tok, UnaryOperator.Opcode.Not, s.E)));
}
@@ -12355,13 +12994,13 @@ namespace Microsoft.Dafny {
} else if (expr is BinaryExpr) {
var bin = (BinaryExpr)expr;
if (position && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.And) {
- TrSplitExpr(bin.E0, splits, position, heightLimit, apply_induction, etran);
- TrSplitExpr(bin.E1, splits, position, heightLimit, apply_induction, etran);
+ TrSplitExpr(bin.E0, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
+ TrSplitExpr(bin.E1, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
return true;
} else if (!position && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Or) {
- TrSplitExpr(bin.E0, splits, position, heightLimit, apply_induction, etran);
- TrSplitExpr(bin.E1, splits, position, heightLimit, apply_induction, etran);
+ TrSplitExpr(bin.E0, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
+ TrSplitExpr(bin.E1, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
return true;
} else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Imp) {
@@ -12369,14 +13008,14 @@ namespace Microsoft.Dafny {
if (position) {
var lhs = etran.TrExpr(bin.E0);
var ss = new List<SplitExprInfo>();
- TrSplitExpr(bin.E1, ss, position, heightLimit, apply_induction, etran);
+ TrSplitExpr(bin.E1, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
foreach (var s in ss) {
// as the source location in the following implication, use that of the translated "s"
splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, lhs, s.E)));
}
} else {
var ss = new List<SplitExprInfo>();
- TrSplitExpr(bin.E0, ss, !position, heightLimit, apply_induction, etran);
+ TrSplitExpr(bin.E0, ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
var rhs = etran.TrExpr(bin.E1);
foreach (var s in ss) {
// as the source location in the following implication, use that of the translated "s"
@@ -12401,15 +13040,14 @@ namespace Microsoft.Dafny {
// checked $PrefixEqual#Dt(k, A, B) || (0 < k ==> A.Cons? ==> B.Cons? && A.head == B.head && $PrefixEqual#2#Dt(k - 1, A.tail, B.tail)) // note the #2 in the recursive call, just like for user-defined predicates that are inlined by TrSplitExpr
// free $PrefixEqual#Dt(k, A, B);
var kPos = Bpl.Expr.Lt(Bpl.Expr.Literal(0), k);
- var prefixEqK = CoEqualCall(codecl, e1type.TypeArgs, e2type.TypeArgs, k, etran.LayerN(2), A, B); // FunctionCall(expr.tok, CoPrefixName(codecl, 1), Bpl.Type.Bool, k, A, B);
+ var prefixEqK = CoEqualCall(codecl, e1type.TypeArgs, e2type.TypeArgs, k, etran.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), A, B); // FunctionCall(expr.tok, CoPrefixName(codecl, 1), Bpl.Type.Bool, k, A, B);
var kMinusOne = Bpl.Expr.Sub(k, Bpl.Expr.Literal(1));
// for the inlining of the definition of prefix equality, translate the two main equality operands arguments with a higher offset (to obtain #2 functions)
var etran2 = etran.LayerOffset(1);
var A2 = etran2.TrExpr(e.E1);
var B2 = etran2.TrExpr(e.E2);
var needsTokenAdjust = TrSplitNeedsTokenAdjustment(expr);
- // Dan: dafny4/Circ.dfy needs this one to be 2+, rather than 1+
- Bpl.Expr layer = LayerSucc(etran.layerInterCluster, 2);
+ Bpl.Expr layer = etran.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH);
foreach (var c in CoPrefixEquality(needsTokenAdjust ? new ForceCheckToken(expr.tok) : expr.tok, codecl, e1type.TypeArgs, e2type.TypeArgs, kMinusOne, layer, A2, B2, true)) {
var p = Bpl.Expr.Binary(c.tok, BinaryOperator.Opcode.Or, prefixEqK, Bpl.Expr.Imp(kPos, c));
splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));
@@ -12424,8 +13062,8 @@ namespace Microsoft.Dafny {
var ssThen = new List<SplitExprInfo>();
var ssElse = new List<SplitExprInfo>();
- TrSplitExpr(ite.Thn, ssThen, position, heightLimit, apply_induction, etran);
- TrSplitExpr(ite.Els, ssElse, position, heightLimit, apply_induction, etran);
+ TrSplitExpr(ite.Thn, ssThen, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
+ TrSplitExpr(ite.Els, ssElse, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
var op = position ? BinaryOperator.Opcode.Imp : BinaryOperator.Opcode.And;
var test = etran.TrExpr(ite.Test);
@@ -12451,14 +13089,14 @@ namespace Microsoft.Dafny {
if (position) {
var conclusion = etran.TrExpr(e.GetSConclusion());
var ss = new List<SplitExprInfo>();
- TrSplitExpr(e.E, ss, position, heightLimit, apply_induction, etran);
+ TrSplitExpr(e.E, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
foreach (var s in ss) {
// as the source location in the following implication, use that of the translated "s"
splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, conclusion, s.E)));
}
} else {
var ss = new List<SplitExprInfo>();
- TrSplitExpr(e.GetSConclusion(), ss, !position, heightLimit, apply_induction, etran);
+ TrSplitExpr(e.GetSConclusion(), ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
var rhs = etran.TrExpr(e.E);
foreach (var s in ss) {
// as the source location in the following implication, use that of the translated "s"
@@ -12469,7 +13107,7 @@ namespace Microsoft.Dafny {
} else if (expr is OldExpr) {
var e = (OldExpr)expr;
- return TrSplitExpr(e.E, splits, position, heightLimit, apply_induction, etran.Old);
+ return TrSplitExpr(e.E, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran.Old);
} else if (expr is FunctionCallExpr && position) {
var fexp = (FunctionCallExpr)expr;
@@ -12478,20 +13116,17 @@ namespace Microsoft.Dafny {
var module = f.EnclosingClass.Module;
var functionHeight = module.CallGraph.GetSCCRepresentativeId(f);
- if (module == currentModule && functionHeight < heightLimit && f.Body != null && !(f.Body.Resolved is MatchExpr)) {
+ if (functionHeight < heightLimit && f.Body != null && !(f.Body.Resolved is MatchExpr)) {
if (RefinementToken.IsInherited(fexp.tok, currentModule) &&
f is Predicate && ((Predicate)f).BodyOrigin == Predicate.BodyOriginKind.DelayedDefinition &&
(codeContext == null || !codeContext.MustReverify)) {
// The function was inherited as body-less but is now given a body. Don't inline the body (since, apparently, everything
// that needed to be proved about the function was proved already in the previous module, even without the body definition).
- } else if (!FunctionBodyIsAvailable(f, currentModule)) {
+ } else if (!FunctionBodyIsAvailable(f, currentModule, inlineProtectedFunctions)) {
// Don't inline opaque functions or foreign protected functions
+ } else if (Attributes.Contains(f.Attributes, "no_inline")) {
+ // User manually prevented inlining
} else {
- // inline this body
- var body = GetSubstitutedBody(fexp, f, false);
- var typeSpecializedBody = GetSubstitutedBody(fexp, f, true);
- var typeSpecializedResultType = Resolver.SubstType(f.ResultType, fexp.TypeArgumentSubstitutions);
-
// Produce, for a "body" split into b0, b1, b2:
// checked F#canCall(args) ==> F(args) || b0
// checked F#canCall(args) ==> F(args) || b1
@@ -12514,49 +13149,68 @@ namespace Microsoft.Dafny {
// F(args)
fargs = etran.TrExpr(fexp);
- // recurse on body
- var ss = new List<SplitExprInfo>();
- TrSplitExpr(typeSpecializedBody, ss, position, functionHeight, apply_induction, etran);
- var needsTokenAdjust = TrSplitNeedsTokenAdjustment(typeSpecializedBody);
- foreach (var s in ss) {
- if (s.IsChecked) {
- var unboxedConjunct = CondApplyUnbox(s.E.tok, s.E, typeSpecializedResultType, expr.Type);
- var bodyOrConjunct = Bpl.Expr.Or(fargs, unboxedConjunct);
- var tok = needsTokenAdjust ? (IToken)new ForceCheckToken(typeSpecializedBody.tok) : (IToken)new NestedToken(fexp.tok, s.E.tok);
- var p = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Imp, canCall, bodyOrConjunct);
- splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));
+ if (!CanSafelyInline(fexp, f)) {
+ // Skip inlining, as it would cause arbitrary expressions to pop up in the trigger
+ // TODO this should appear at the outmost call site, not at the innermost. See SnapshotableTrees.dfy
+ reporter.Info(MessageSource.Translator, fexp.tok, "Some instances of this call cannot safely be inlined.");
+ // F#canCall(args) ==> F(args)
+ var p = Bpl.Expr.Binary(fargs.tok, BinaryOperator.Opcode.Imp, canCall, fargs);
+ splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));
+ // F#canCall(args) && F(args)
+ var fr = Bpl.Expr.And(canCall, fargs);
+ splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, fr));
+
+ } else {
+ // inline this body
+ var typeSpecializedBody = GetSubstitutedBody(fexp, f);
+ var typeSpecializedResultType = Resolver.SubstType(f.ResultType, fexp.TypeArgumentSubstitutions);
+
+ // recurse on body
+ var ss = new List<SplitExprInfo>();
+ TrSplitExpr(typeSpecializedBody, ss, position, functionHeight, inlineProtectedFunctions, apply_induction, etran);
+ var needsTokenAdjust = TrSplitNeedsTokenAdjustment(typeSpecializedBody);
+ foreach (var s in ss) {
+ if (s.IsChecked) {
+ var unboxedConjunct = CondApplyUnbox(s.E.tok, s.E, typeSpecializedResultType, expr.Type);
+ var bodyOrConjunct = Bpl.Expr.Or(fargs, unboxedConjunct);
+ var tok = needsTokenAdjust ? (IToken)new ForceCheckToken(typeSpecializedBody.tok) : (IToken)new NestedToken(fexp.tok, s.E.tok);
+ var p = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Imp, canCall, bodyOrConjunct);
+ splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));
+ }
}
- }
- // allocatedness for arguments to the inlined call in body
- if (typeSpecializedBody is FunctionCallExpr) {
- FunctionCallExpr e = (FunctionCallExpr)typeSpecializedBody;
- for (int i = 0; i < e.Args.Count; i++) {
- Expression ee = e.Args[i];
- Type t = e.Function.Formals[i].Type;
- Expr tr_ee = etran.TrExpr(ee);
- Bpl.Expr wh = GetWhereClause(e.tok, tr_ee, cce.NonNull(ee.Type), etran);
- if (wh != null) { fargs = Bpl.Expr.And(fargs, wh); }
+ // allocatedness for arguments to the inlined call in body
+ if (typeSpecializedBody is FunctionCallExpr) {
+ FunctionCallExpr e = (FunctionCallExpr)typeSpecializedBody;
+ for (int i = 0; i < e.Args.Count; i++) {
+ Expression ee = e.Args[i];
+ Type t = e.Function.Formals[i].Type;
+ Expr tr_ee = etran.TrExpr(ee);
+ Bpl.Expr wh = GetWhereClause(e.tok, tr_ee, cce.NonNull(ee.Type), etran);
+ if (wh != null) { fargs = Bpl.Expr.And(fargs, wh); }
+ }
}
- }
- // body
- var trBody = etran.TrExpr(typeSpecializedBody);
- trBody = CondApplyUnbox(trBody.tok, trBody, typeSpecializedResultType, expr.Type);
- // F#canCall(args) && F(args) && (b0 && b1 && b2)
- var fr = Bpl.Expr.And(canCall, BplAnd(fargs, trBody));
- splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, fr));
+ // body
+ var trBody = etran.TrExpr(typeSpecializedBody);
+ trBody = CondApplyUnbox(trBody.tok, trBody, typeSpecializedResultType, expr.Type);
+ // F#canCall(args) && F(args) && (b0 && b1 && b2)
+ var fr = Bpl.Expr.And(canCall, BplAnd(fargs, trBody));
+ splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, fr));
+ }
return true;
}
}
+ } else if (expr is QuantifierExpr && ((QuantifierExpr)expr).SplitQuantifier != null) {
+ return TrSplitExpr(((QuantifierExpr)expr).SplitQuantifierExpression, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);
} else if (((position && expr is ForallExpr) || (!position && expr is ExistsExpr))
- /* NB: only for type arg less quantifiers for now: */
- && ((QuantifierExpr)expr).TypeArgs.Count == 0) {
+ /* NB: only for type arg less quantifiers for now: */
+ && ((QuantifierExpr)expr).TypeArgs.Count == 0) {
var e = (QuantifierExpr)expr;
- var inductionVariables = ApplyInduction(e);
- if (apply_induction && 2 <= DafnyOptions.O.Induction && inductionVariables.Count != 0) {
+ var inductionVariables = ApplyInduction(e.BoundVars, e.Attributes);
+ if (apply_induction && inductionVariables.Count != 0) {
// From the given quantifier (forall n :: P(n)), generate the seemingly weaker proof obligation
// (forall n :: (forall k :: k < n ==> P(k)) ==> P(n))
// For an existential (exists n :: P(n)), it is
@@ -12595,12 +13249,8 @@ namespace Microsoft.Dafny {
List<Variable> bvars = new List<Variable>();
Bpl.Expr typeAntecedent = etran.TrBoundVariables(kvars, bvars);
Bpl.Expr ih;
- if (Attributes.Contains(e.Attributes, "trigger")) {
- Bpl.Trigger tr = TrTrigger(etran, e.Attributes, expr.tok, substMap);
- ih = new Bpl.ForallExpr(expr.tok, bvars, tr, Bpl.Expr.Imp(typeAntecedent, ihBody));
- } else {
- ih = new Bpl.ForallExpr(expr.tok, bvars, Bpl.Expr.Imp(typeAntecedent, ihBody));
- }
+ var tr = TrTrigger(etran, e.Attributes, expr.tok, substMap);
+ ih = new Bpl.ForallExpr(expr.tok, bvars, tr, Bpl.Expr.Imp(typeAntecedent, ihBody));
// More precisely now:
// (forall n :: n-has-expected-type && (forall k :: k < n ==> P(k)) && case0(n) ==> P(n))
@@ -12629,17 +13279,14 @@ namespace Microsoft.Dafny {
typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars);
foreach (var kase in caseProduct) {
var ante = BplAnd(BplAnd(typeAntecedent, ih), kase);
- var bdy = etran.LayerOffset(1).TrExpr(e.LogicalBody());
+ var etranBody = etran.LayerOffset(1);
+ var bdy = etranBody.TrExpr(e.LogicalBody());
Bpl.Expr q;
+ var trig = TrTrigger(etranBody, e.Attributes, expr.tok);
if (position) {
- if (Attributes.Contains(e.Attributes, "trigger")) {
- Bpl.Trigger tr = TrTrigger(etran, e.Attributes, expr.tok);
- q = new Bpl.ForallExpr(kase.tok, bvars, tr, Bpl.Expr.Imp(ante, bdy));
- } else {
- q = new Bpl.ForallExpr(kase.tok, bvars, Bpl.Expr.Imp(ante, bdy));
- }
+ q = new Bpl.ForallExpr(kase.tok, bvars, trig, Bpl.Expr.Imp(ante, bdy));
} else {
- q = new Bpl.ExistsExpr(kase.tok, bvars, Bpl.Expr.And(ante, bdy));
+ q = new Bpl.ExistsExpr(kase.tok, bvars, trig, Bpl.Expr.And(ante, bdy));
}
splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, q));
}
@@ -12676,8 +13323,10 @@ namespace Microsoft.Dafny {
translatedExpression = etran.TrExpr(expr);
splitHappened = false;
} else {
+ // for quantifierExpr, we don't want to increase fuel in assert context
+ var existEtran = etran;
etran = etran.LayerOffset(1);
- translatedExpression = etran.TrExpr(expr);
+ translatedExpression = etran.TrExpr(expr, null, etran, existEtran);
splitHappened = etran.Statistics_CustomLayerFunctionCount != 0; // return true if the LayerOffset(1) came into play
}
if (TrSplitNeedsTokenAdjustment(expr)) {
@@ -12688,14 +13337,62 @@ namespace Microsoft.Dafny {
return splitHappened;
}
- private Expression GetSubstitutedBody(FunctionCallExpr fexp, Function f, bool specializeTypeParameters) {
+ private bool CanSafelyInline(FunctionCallExpr fexp, Function f) {
+ var visitor = new TriggersExplorer();
+ visitor.Visit(f);
+ return f.Formals.Zip(fexp.Args).All(formal_concrete => CanSafelySubstitute(visitor.TriggerVariables, formal_concrete.Item1, formal_concrete.Item2));
+ }
+
+ // Using an empty set of old expressions is ok here; the only uses of the triggersCollector will be to check for trigger killers.
+ Triggers.TriggersCollector triggersCollector = new Triggers.TriggersCollector(new HashSet<Expression>());
+
+ private bool CanSafelySubstitute(ISet<IVariable> protectedVariables, IVariable variable, Expression substitution) {
+ return !(protectedVariables.Contains(variable) && triggersCollector.IsTriggerKiller(substitution));
+ }
+
+ private class VariablesCollector: BottomUpVisitor {
+ internal ISet<IVariable> variables;
+
+ internal VariablesCollector() {
+ this.variables = new HashSet<IVariable>();
+ }
+
+ protected override void VisitOneExpr(Expression expr) {
+ if (expr is IdentifierExpr) {
+ variables.Add((expr as IdentifierExpr).Var);
+ }
+ }
+ }
+
+ private class TriggersExplorer : BottomUpVisitor {
+ VariablesCollector collector;
+
+ internal ISet<IVariable> TriggerVariables { get { return collector.variables; } }
+
+ internal TriggersExplorer() {
+ collector = new VariablesCollector();
+ }
+
+ protected override void VisitOneExpr(Expression expr) {
+ if (expr is QuantifierExpr) {
+ var e = (QuantifierExpr)expr;
+ if (e.SplitQuantifier == null) {
+ foreach (var trigger in (expr as QuantifierExpr).Attributes.AsEnumerable().Where(a => a.Name == "trigger").SelectMany(a => a.Args)) {
+ collector.Visit(trigger);
+ }
+ }
+ }
+ }
+ }
+
+ private Expression GetSubstitutedBody(FunctionCallExpr fexp, Function f) {
Contract.Requires(fexp != null);
Contract.Requires(f != null);
var substMap = new Dictionary<IVariable, Expression>();
Contract.Assert(fexp.Args.Count == f.Formals.Count);
for (int i = 0; i < f.Formals.Count; i++) {
Formal p = f.Formals[i];
- var formalType = specializeTypeParameters ? Resolver.SubstType(p.Type, fexp.TypeArgumentSubstitutions) : p.Type;
+ var formalType = Resolver.SubstType(p.Type, fexp.TypeArgumentSubstitutions);
Expression arg = fexp.Args[i];
arg = new BoxingCastExpr(arg, cce.NonNull(arg.Type), formalType);
arg.Type = formalType; // resolve here
@@ -12706,7 +13403,7 @@ namespace Microsoft.Dafny {
var pp = (PrefixPredicate)f;
body = PrefixSubstitution(pp, body);
}
- body = Substitute(body, fexp.Receiver, substMap, specializeTypeParameters ? fexp.TypeArgumentSubstitutions : null);
+ body = Substitute(body, fexp.Receiver, substMap, fexp.TypeArgumentSubstitutions);
return body;
}
@@ -12715,297 +13412,29 @@ namespace Microsoft.Dafny {
return RefinementToken.IsInherited(expr.tok, currentModule) && (codeContext == null || !codeContext.MustReverify) && RefinementTransformer.ContainsChange(expr, currentModule);
}
- List<BoundVar> ApplyInduction(QuantifierExpr e) {
- Contract.Requires(e.TypeArgs.Count == 0);
- return ApplyInduction(e.BoundVars, e.Attributes, new List<Expression>() { e.LogicalBody() },
- delegate(System.IO.TextWriter wr) { new Printer(wr).PrintExpression(e, true); });
- }
-
- delegate void TracePrinter(System.IO.TextWriter wr);
-
/// <summary>
/// Return a subset of "boundVars" (in the order giving in "boundVars") to which to apply induction to,
- /// according to :induction attributes in "attributes" and heuristically interesting subexpressions of
- /// "searchExprs".
+ /// according to :_induction attribute in "attributes".
/// </summary>
- List<VarType> ApplyInduction<VarType>(List<VarType> boundVars, Attributes attributes, List<Expression> searchExprs, TracePrinter tracePrinter) where VarType : class, IVariable
+ List<VarType> ApplyInduction<VarType>(List<VarType> boundVars, Attributes attributes) where VarType : class, IVariable
{
Contract.Requires(boundVars != null);
- Contract.Requires(searchExprs != null);
- Contract.Requires(tracePrinter != null);
Contract.Ensures(Contract.Result<List<VarType>>() != null);
- if (DafnyOptions.O.Induction == 0) {
- return new List<VarType>(); // don't apply induction
- }
-
- for (var a = attributes; a != null; a = a.Prev) {
- if (a.Name == "induction") {
- // Here are the supported forms of the :induction attribute.
- // :induction -- apply induction to all bound variables
- // :induction false -- suppress induction, that is, don't apply it to any bound variable
- // :induction L where L is a list consisting entirely of bound variables:
- // -- apply induction to the specified bound variables
- // :induction X where X is anything else
- // -- treat the same as {:induction}, that is, apply induction to all
- // bound variables
-
- // Handle {:induction false}
- if (a.Args.Count == 1) {
- var arg = a.Args[0] as LiteralExpr;
- if (arg != null && arg.Value is bool && !(bool)arg.Value) {
- if (CommandLineOptions.Clo.Trace) {
- Console.Write("Suppressing automatic induction for: ");
- tracePrinter(Console.Out);
- Console.WriteLine();
- }
- return new List<VarType>();
- }
- }
-
- // Handle {:induction L}
- if (a.Args.Count != 0) {
- // check that all attribute arguments refer to bound variables; otherwise, go to default_form
- var argsAsVars = new List<VarType>();
- foreach (var arg in a.Args) {
- var theArg = arg.Resolved;
- if (theArg is ThisExpr) {
- foreach (var bv in boundVars) {
- if (bv is ThisSurrogate) {
- argsAsVars.Add(bv);
- goto TRY_NEXT_ATTRIBUTE_ARGUMENT;
- }
- }
- } else if (theArg is IdentifierExpr) {
- var id = (IdentifierExpr)theArg;
- var bv = id.Var as VarType;
- if (bv != null && boundVars.Contains(bv)) {
- argsAsVars.Add(bv);
- goto TRY_NEXT_ATTRIBUTE_ARGUMENT;
- }
- }
- // the attribute argument was not one of the possible induction variables
- goto USE_DEFAULT_FORM;
- TRY_NEXT_ATTRIBUTE_ARGUMENT:
- ;
- }
- // so, all attribute arguments are variables; add them to L in the order of the bound variables (not necessarily the order in the attribute)
- var L = new List<VarType>();
- foreach (var bv in boundVars) {
- if (argsAsVars.Contains(bv)) {
- L.Add(bv);
- }
- }
- if (CommandLineOptions.Clo.Trace) {
- string sep = "Applying requested induction on ";
- foreach (var bv in L) {
- Console.Write("{0}{1}", sep, bv.Name);
- sep = ", ";
- }
- Console.Write(" of: ");
- tracePrinter(Console.Out);
- Console.WriteLine();
- }
- return L;
- USE_DEFAULT_FORM: ;
- }
-
- // We have the {:induction} case, or something to be treated in the same way
- if (CommandLineOptions.Clo.Trace) {
- Console.Write("Applying requested induction on all bound variables of: ");
- tracePrinter(Console.Out);
- Console.WriteLine();
- }
- return boundVars;
- }
- }
-
- if (DafnyOptions.O.Induction < 2) {
+ var args = Attributes.FindExpressions(attributes, "_induction");
+ if (args == null) {
return new List<VarType>(); // don't apply induction
}
- // consider automatically applying induction
- var inductionVariables = new List<VarType>();
- foreach (var n in boundVars) {
- if (!n.Type.IsTypeParameter && searchExprs.Exists(expr => VarOccursInArgumentToRecursiveFunction(expr, n))) {
- if (CommandLineOptions.Clo.Trace) {
- Console.Write("Applying automatic induction on variable '{0}' of: ", n.Name);
- tracePrinter(Console.Out);
- Console.WriteLine();
- }
- inductionVariables.Add(n);
- }
- }
-
- return inductionVariables;
- }
-
- /// <summary>
- /// Returns 'true' iff by looking at 'expr' the Induction Heuristic determines that induction should be applied to 'n'.
- /// More precisely:
- /// DafnyInductionHeuristic Return 'true'
- /// ----------------------- -------------
- /// 0 always
- /// 1 if 'n' occurs as any subexpression (of 'expr')
- /// 2 if 'n' occurs as any subexpression of any index argument of an array/sequence select expression or any argument to a recursive function
- /// 3 if 'n' occurs as a prominent subexpression of any index argument of an array/sequence select expression or any argument to a recursive function
- /// 4 if 'n' occurs as any subexpression of any argument to a recursive function
- /// 5 if 'n' occurs as a prominent subexpression of any argument to a recursive function
- /// 6 if 'n' occurs as a prominent subexpression of any decreases-influencing argument to a recursive function
- /// Parameter 'n' is allowed to be a ThisSurrogate.
- /// </summary>
- bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n) {
- switch (DafnyOptions.O.InductionHeuristic) {
- case 0: return true;
- case 1: return ContainsFreeVariable(expr, false, n);
- default: return VarOccursInArgumentToRecursiveFunction(expr, n, false);
- }
- }
-
- /// <summary>
- /// Worker routine for VarOccursInArgumentToRecursiveFunction(expr,n), where the additional parameter 'exprIsProminent' says whether or
- /// not 'expr' has prominent status in its context.
- /// DafnyInductionHeuristic cases 0 and 1 are assumed to be handled elsewhere (i.e., a precondition of this method is DafnyInductionHeuristic is at least 2).
- /// Parameter 'n' is allowed to be a ThisSurrogate.
- /// </summary>
- bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n, bool exprIsProminent) {
- Contract.Requires(expr != null);
- Contract.Requires(n != null);
-
- // The following variable is what gets passed down to recursive calls if the subexpression does not itself acquire prominent status.
- var subExprIsProminent = DafnyOptions.O.InductionHeuristic == 2 || DafnyOptions.O.InductionHeuristic == 4 ? /*once prominent, always prominent*/exprIsProminent : /*reset the prominent status*/false;
-
- if (expr is ThisExpr) {
- return exprIsProminent && n is ThisSurrogate;
- } else if (expr is IdentifierExpr) {
- var e = (IdentifierExpr)expr;
- return exprIsProminent && e.Var == n;
- } else if (expr is SeqSelectExpr) {
- var e = (SeqSelectExpr)expr;
- var q = DafnyOptions.O.InductionHeuristic < 4 || subExprIsProminent;
- return VarOccursInArgumentToRecursiveFunction(e.Seq, n, subExprIsProminent) || // this subexpression does not acquire "prominent" status
- (e.E0 != null && VarOccursInArgumentToRecursiveFunction(e.E0, n, q)) || // this one does (unless arrays/sequences are excluded)
- (e.E1 != null && VarOccursInArgumentToRecursiveFunction(e.E1, n, q)); // ditto
- } else if (expr is MultiSelectExpr) {
- var e = (MultiSelectExpr)expr;
- var q = DafnyOptions.O.InductionHeuristic < 4 || subExprIsProminent;
- return VarOccursInArgumentToRecursiveFunction(e.Array, n, subExprIsProminent) ||
- e.Indices.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));
- } else if (expr is FunctionCallExpr) {
- var e = (FunctionCallExpr)expr;
- // For recursive functions: arguments are "prominent"
- // For non-recursive function: arguments are "prominent" if the call is
- var rec = e.Function.IsRecursive && e.CoCall != FunctionCallExpr.CoCallResolution.Yes;
- var decr = e.Function.Decreases.Expressions;
- bool variantArgument;
- if (DafnyOptions.O.InductionHeuristic < 6) {
- variantArgument = rec;
- } else {
- // The receiver is considered to be "variant" if the function is recursive and the receiver participates
- // in the effective decreases clause of the function. The receiver participates if it's a free variable
- // of a term in the explicit decreases clause.
- variantArgument = rec && decr.Exists(ee => ContainsFreeVariable(ee, true, null));
- }
- if (VarOccursInArgumentToRecursiveFunction(e.Receiver, n, variantArgument || subExprIsProminent)) {
- return true;
- }
- Contract.Assert(e.Function.Formals.Count == e.Args.Count);
- for (int i = 0; i < e.Function.Formals.Count; i++) {
- var f = e.Function.Formals[i];
- var exp = e.Args[i];
- if (DafnyOptions.O.InductionHeuristic < 6) {
- variantArgument = rec;
- } else if (rec) {
- // The argument position is considered to be "variant" if the function is recursive and...
- // ... it has something to do with why the callee is well-founded, which happens when...
- if (f is ImplicitFormal) {
- // ... it is the argument is the implicit _k parameter, which is always first in the effective decreases clause of a prefix lemma, or
- variantArgument = true;
- } else if (decr.Exists(ee => ContainsFreeVariable(ee, false, f))) {
- // ... it participates in the effective decreases clause of the function, which happens when it is
- // a free variable of a term in the explicit decreases clause, or
- variantArgument = true;
- } else {
- // ... the callee is a prefix predicate.
- variantArgument = true;
- }
- }
- if (VarOccursInArgumentToRecursiveFunction(exp, n, variantArgument || subExprIsProminent)) {
- return true;
- }
- }
- return false;
- } else if (expr is TernaryExpr) {
- var e = (TernaryExpr)expr;
- switch (e.Op) {
- case TernaryExpr.Opcode.PrefixEqOp:
- case TernaryExpr.Opcode.PrefixNeqOp:
- return VarOccursInArgumentToRecursiveFunction(e.E0, n, true) ||
- VarOccursInArgumentToRecursiveFunction(e.E1, n, subExprIsProminent) ||
- VarOccursInArgumentToRecursiveFunction(e.E2, n, subExprIsProminent);
- default:
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected ternary expression
- }
- } else if (expr is DatatypeValue) {
- var e = (DatatypeValue)expr;
- var q = n.Type.IsDatatype ? exprIsProminent : subExprIsProminent; // prominent status continues, if we're looking for a variable whose type is a datatype
- return e.Arguments.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));
- } else if (expr is UnaryExpr) {
- var e = (UnaryExpr)expr;
- // both Not and SeqLength preserve prominence
- return VarOccursInArgumentToRecursiveFunction(e.E, n, exprIsProminent);
- } else if (expr is BinaryExpr) {
- var e = (BinaryExpr)expr;
- bool q;
- switch (e.ResolvedOp) {
- case BinaryExpr.ResolvedOpcode.Add:
- case BinaryExpr.ResolvedOpcode.Sub:
- case BinaryExpr.ResolvedOpcode.Mul:
- case BinaryExpr.ResolvedOpcode.Div:
- case BinaryExpr.ResolvedOpcode.Mod:
- case BinaryExpr.ResolvedOpcode.Union:
- case BinaryExpr.ResolvedOpcode.Intersection:
- case BinaryExpr.ResolvedOpcode.SetDifference:
- case BinaryExpr.ResolvedOpcode.Concat:
- // these operators preserve prominence
- q = exprIsProminent;
- break;
- default:
- // whereas all other binary operators do not
- q = subExprIsProminent;
- break;
- }
- return VarOccursInArgumentToRecursiveFunction(e.E0, n, q) ||
- VarOccursInArgumentToRecursiveFunction(e.E1, n, q);
- } else if (expr is StmtExpr) {
- var e = (StmtExpr)expr;
- // ignore the statement
- return VarOccursInArgumentToRecursiveFunction(e.E, n);
-
- } else if (expr is ITEExpr) {
- var e = (ITEExpr)expr;
- return VarOccursInArgumentToRecursiveFunction(e.Test, n, subExprIsProminent) || // test is not "prominent"
- VarOccursInArgumentToRecursiveFunction(e.Thn, n, exprIsProminent) || // but the two branches are
- VarOccursInArgumentToRecursiveFunction(e.Els, n, exprIsProminent);
- } else if (expr is OldExpr ||
- expr is ConcreteSyntaxExpression ||
- expr is BoxingCastExpr ||
- expr is UnboxingCastExpr) {
- foreach (var exp in expr.SubExpressions) {
- if (VarOccursInArgumentToRecursiveFunction(exp, n, exprIsProminent)) { // maintain prominence
- return true;
- }
- }
- return false;
- } else {
- // in all other cases, reset the prominence status and recurse on the subexpressions
- foreach (var exp in expr.SubExpressions) {
- if (VarOccursInArgumentToRecursiveFunction(exp, n, subExprIsProminent)) {
- return true;
- }
- }
- return false;
+ var argsAsVars = new List<VarType>();
+ foreach (var arg in args) {
+ // We expect each "arg" to be an IdentifierExpr among "boundVars"
+ var id = (IdentifierExpr)arg;
+ var bv = (VarType)id.Var;
+ Contract.Assume(boundVars.Contains(bv));
+ argsAsVars.Add(bv);
}
+ return argsAsVars;
}
IEnumerable<Bpl.Expr> InductionCases(Type ty, Bpl.Expr expr, ExpressionTranslator etran) {
@@ -13039,7 +13468,8 @@ namespace Microsoft.Dafny {
}
i++;
}
- q = new Bpl.ExistsExpr(ctor.tok, bvs, BplAnd(typeAntecedent, q));
+ var trigger = BplTrigger(ct); // this is probably never used, because this quantifier is not expected ever to appear in a context where it needs to be instantiated
+ q = new Bpl.ExistsExpr(ctor.tok, bvs, trigger, BplAnd(typeAntecedent, q));
}
yield return q;
}
@@ -13051,12 +13481,12 @@ namespace Microsoft.Dafny {
/// Parameter 'v' is allowed to be a ThisSurrogate, in which case the method return true iff 'this'
/// occurs in 'expr'.
/// </summary>
- static bool ContainsFreeVariable(Expression expr, bool lookForReceiver, IVariable v) {
+ public static bool ContainsFreeVariable(Expression expr, bool lookForReceiver, IVariable v) {
Contract.Requires(expr != null);
Contract.Requires(lookForReceiver || v != null);
if (expr is ThisExpr) {
- return lookForReceiver || v is ThisSurrogate;
+ return lookForReceiver;
} else if (expr is IdentifierExpr) {
IdentifierExpr e = (IdentifierExpr)expr;
return e.Var == v;
@@ -13083,7 +13513,20 @@ namespace Microsoft.Dafny {
ty.NormalizeExpand().TypeArgs.Iter(tt => ComputeFreeTypeVariables(tt, fvs));
}
- public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap, ref bool usesOldHeap, ref Type usesThis, bool inOldContext) {
+ public static ISet<IVariable> ComputeFreeVariables(Expression expr) {
+ Contract.Requires(expr != null);
+ ISet<IVariable> fvs = new HashSet<IVariable>();
+ ComputeFreeVariables(expr, fvs);
+ return fvs;
+ }
+ public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs) {
+ Contract.Requires(expr != null);
+ Contract.Requires(fvs != null);
+ bool dontCare0 = false, dontCare1 = false;
+ Type dontCareT = null;
+ ComputeFreeVariables(expr, fvs, ref dontCare0, ref dontCare1, ref dontCareT);
+ }
+ public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap, ref bool usesOldHeap, ref Type usesThis) {
Contract.Requires(expr != null);
if (expr is ThisExpr) {
@@ -13094,13 +13537,6 @@ namespace Microsoft.Dafny {
var e = (IdentifierExpr)expr;
fvs.Add(e.Var);
return;
- } else if (expr is OldExpr) {
- var e = (OldExpr)expr;
- bool subUsesHeap = false;
- ComputeFreeVariables(e.E, fvs, ref subUsesHeap, ref usesOldHeap, ref usesThis, true);
- if (subUsesHeap) {
- usesOldHeap = true;
- }
} else if (expr is MemberSelectExpr) {
usesHeap = true;
} else if (expr is SeqSelectExpr) {
@@ -13124,11 +13560,11 @@ namespace Microsoft.Dafny {
// visit subexpressions
bool uHeap = false, uOldHeap = false;
Type uThis = null;
- expr.SubExpressions.Iter(ee => ComputeFreeVariables(ee, fvs, ref uHeap, ref uOldHeap, ref uThis, inOldContext));
+ expr.SubExpressions.Iter(ee => ComputeFreeVariables(ee, fvs, ref uHeap, ref uOldHeap, ref uThis));
Contract.Assert(usesThis == null || uThis == null || usesThis.Equals(uThis));
usesThis = usesThis ?? uThis;
usesHeap |= uHeap;
- usesOldHeap |= uOldHeap;
+ usesOldHeap |= expr is OldExpr ? uHeap | uOldHeap : uOldHeap;
if (expr is LetExpr) {
var e = (LetExpr)expr;
@@ -13256,7 +13692,7 @@ namespace Microsoft.Dafny {
List<Expression> newElements = SubstituteExprList(e.Elements);
if (newElements != e.Elements) {
if (expr is SetDisplayExpr) {
- newExpr = new SetDisplayExpr(expr.tok, newElements);
+ newExpr = new SetDisplayExpr(expr.tok, ((SetDisplayExpr)expr).Finite, newElements);
} else if (expr is MultiSetDisplayExpr) {
newExpr = new MultiSetDisplayExpr(expr.tok, newElements);
} else {
@@ -13421,6 +13857,7 @@ namespace Microsoft.Dafny {
if (newCasePatterns != e.LHSs) {
anythingChanged = true;
}
+
var body = Substitute(e.Body);
// undo any changes to substMap (could be optimized to do this only if newBoundVars != e.Vars)
foreach (var bv in e.BoundVars) {
@@ -13482,13 +13919,19 @@ namespace Microsoft.Dafny {
var e = (ComprehensionExpr)expr;
// For quantifiers and setComprehesion we want to make sure that we don't introduce name clashes with
// the enclosing scopes.
+
+ var q = e as QuantifierExpr;
+ if (q != null && q.SplitQuantifier != null) {
+ return Substitute(q.SplitQuantifierExpression);
+ }
+
var newBoundVars = CreateBoundVarSubstitutions(e.BoundVars, expr is ForallExpr || expr is ExistsExpr || expr is SetComprehension);
- Expression newRange = e.Range == null ? null : Substitute(e.Range);
- Expression newTerm = Substitute(e.Term);
- Attributes newAttrs = SubstAttributes(e.Attributes);
+ var newRange = e.Range == null ? null : Substitute(e.Range);
+ var newTerm = Substitute(e.Term);
+ var newAttrs = SubstAttributes(e.Attributes);
if (newBoundVars != e.BoundVars || newRange != e.Range || newTerm != e.Term || newAttrs != e.Attributes) {
if (e is SetComprehension) {
- newExpr = new SetComprehension(expr.tok, newBoundVars, newRange, newTerm, newAttrs);
+ newExpr = new SetComprehension(expr.tok, ((SetComprehension)e).Finite, newBoundVars, newRange, newTerm, newAttrs);
} else if (e is MapComprehension) {
newExpr = new MapComprehension(expr.tok, ((MapComprehension)e).Finite, newBoundVars, newRange, newTerm, newAttrs);
} else if (expr is ForallExpr) {
@@ -13501,6 +13944,9 @@ namespace Microsoft.Dafny {
} else {
Contract.Assert(false); // unexpected ComprehensionExpr
}
+ if (e.Bounds != null) {
+ ((ComprehensionExpr)newExpr).Bounds = e.Bounds.ConvertAll(bound => SubstituteBoundedPool(bound));
+ }
}
// undo any changes to substMap (could be optimized to do this only if newBoundVars != e.BoundVars)
foreach (var bv in e.BoundVars) {
@@ -13558,6 +14004,44 @@ namespace Microsoft.Dafny {
}
}
+ public ComprehensionExpr.BoundedPool SubstituteBoundedPool(ComprehensionExpr.BoundedPool bound) {
+ if (bound == null) {
+ return null;
+ } else if (bound is ComprehensionExpr.ExactBoundedPool) {
+ var b = (ComprehensionExpr.ExactBoundedPool)bound;
+ return new ComprehensionExpr.ExactBoundedPool(Substitute(b.E));
+ } else if (bound is ComprehensionExpr.BoolBoundedPool) {
+ return bound; // nothing to substitute
+ } else if (bound is ComprehensionExpr.CharBoundedPool) {
+ return bound; // nothing to substitute
+ } else if (bound is ComprehensionExpr.RefBoundedPool) {
+ return bound; // nothing to substitute
+ } else if (bound is ComprehensionExpr.IntBoundedPool) {
+ var b = (ComprehensionExpr.IntBoundedPool)bound;
+ return new ComprehensionExpr.IntBoundedPool(b.LowerBound == null ? null : Substitute(b.LowerBound), b.UpperBound == null ? null : Substitute(b.UpperBound));
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var b = (ComprehensionExpr.SetBoundedPool)bound;
+ return new ComprehensionExpr.SetBoundedPool(Substitute(b.Set));
+ } else if (bound is ComprehensionExpr.SubSetBoundedPool) {
+ var b = (ComprehensionExpr.SubSetBoundedPool)bound;
+ return new ComprehensionExpr.SubSetBoundedPool(Substitute(b.UpperBound));
+ } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {
+ var b = (ComprehensionExpr.SuperSetBoundedPool)bound;
+ return new ComprehensionExpr.SuperSetBoundedPool(Substitute(b.LowerBound));
+ } else if (bound is ComprehensionExpr.MapBoundedPool) {
+ var b = (ComprehensionExpr.MapBoundedPool)bound;
+ return new ComprehensionExpr.MapBoundedPool(Substitute(b.Map));
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var b = (ComprehensionExpr.SeqBoundedPool)bound;
+ return new ComprehensionExpr.SeqBoundedPool(Substitute(b.Seq));
+ } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
+ return bound; // nothing to substitute
+ } else {
+ Contract.Assume(false); // unexpected ComprehensionExpr.BoundedPool
+ throw new cce.UnreachableException(); // to please compiler
+ }
+ }
+
/// <summary>
/// Return a list of bound variables, of the same length as 'vars' but with possible substitutions.
/// For any change necessary, update 'substMap' to reflect the new substitution; the caller is responsible for
@@ -13733,7 +14217,7 @@ namespace Microsoft.Dafny {
r = SubstBlockStmt((BlockStmt)stmt);
} else if (stmt is IfStmt) {
var s = (IfStmt)stmt;
- r = new IfStmt(s.Tok, s.EndTok, Substitute(s.Guard), SubstBlockStmt(s.Thn), SubstStmt(s.Els));
+ r = new IfStmt(s.Tok, s.EndTok, s.IsExistentialGuard, Substitute(s.Guard), SubstBlockStmt(s.Thn), SubstStmt(s.Els));
} else if (stmt is AlternativeStmt) {
var s = (AlternativeStmt)stmt;
r = new AlternativeStmt(s.Tok, s.EndTok, s.Alternatives.ConvertAll(SubstGuardedAlternative));
@@ -13757,7 +14241,7 @@ namespace Microsoft.Dafny {
r = rr;
} else if (stmt is CalcStmt) {
var s = (CalcStmt)stmt;
- var rr = new CalcStmt(s.Tok, s.EndTok, SubstCalcOp(s.Op), s.Lines.ConvertAll(Substitute), s.Hints.ConvertAll(SubstBlockStmt), s.StepOps.ConvertAll(SubstCalcOp), SubstCalcOp(s.ResultOp));
+ var rr = new CalcStmt(s.Tok, s.EndTok, SubstCalcOp(s.Op), s.Lines.ConvertAll(Substitute), s.Hints.ConvertAll(SubstBlockStmt), s.StepOps.ConvertAll(SubstCalcOp), SubstCalcOp(s.ResultOp), SubstAttributes(s.Attributes));
rr.Steps.AddRange(s.Steps.ConvertAll(Substitute));
rr.Result = Substitute(s.Result);
r = rr;
@@ -13822,7 +14306,7 @@ namespace Microsoft.Dafny {
protected GuardedAlternative SubstGuardedAlternative(GuardedAlternative alt) {
Contract.Requires(alt != null);
- return new GuardedAlternative(alt.Tok, Substitute(alt.Guard), alt.Body.ConvertAll(SubstStmt));
+ return new GuardedAlternative(alt.Tok, alt.IsExistentialGuard, Substitute(alt.Guard), alt.Body.ConvertAll(SubstStmt));
}
protected MaybeFreeExpression SubstMayBeFreeExpr(MaybeFreeExpression expr) {
@@ -13950,22 +14434,91 @@ namespace Microsoft.Dafny {
Bpl.Expr.Eq(oldHeap, newHeap),
FunctionCall(newHeap.tok, BuiltinFunction.HeapSucc, null, oldHeap, newHeap));
}
+ Bpl.Expr HeapSucc(Bpl.Expr oldHeap, Bpl.Expr newHeap, bool useGhostHeapSucc = false) {
+ return FunctionCall(newHeap.tok, useGhostHeapSucc ? BuiltinFunction.HeapSuccGhost : BuiltinFunction.HeapSucc, null, oldHeap, newHeap);
+ }
// Bpl-making-utilities
+ /// <summary>
+ /// Create a Boogie quantifier with body "A ==> body" and triggers "trg", but use only the subset of bound
+ /// variables from "varsAndAntecedents" that actually occur free in "body" or "trg", and "A" is the conjunction of
+ /// antecedents for those corresponding bound variables. If none of the bound variables is used, "body"
+ /// is returned.
+ /// The order of the contents of "varsAndAntecedents" matters: For any index "i" into "varsAndAntecedents", the
+ /// antecedent varsAndAntecedents[i].Item2 may depend on a variable varsAndAntecedents[j].Item1 if "j GREATER-OR-EQUAL i"
+ /// but not if "j LESS i".
+ /// Caution: if "trg" is null, makes a forall without any triggers.
+ /// </summary>
+ static Bpl.Expr BplForallTrim(IEnumerable<Tuple<Bpl.Variable, Bpl.Expr/*?*/>> varsAndAntecedents, Bpl.Trigger trg, Bpl.Expr body) {
+ Contract.Requires(varsAndAntecedents != null);
+ Contract.Requires(body != null);
+
+ // We'd like to compute the free variables if "body" and "trg". It would be nice to use the Boogie
+ // routine Bpl.Expr.ComputeFreeVariables for this purpose. However, calling it requires the Boogie
+ // expression to be resolved. Instead, we do the cheesy thing of computing the set of names of
+ // free variables in "body" and "trg".
+ var vis = new VariableNameVisitor();
+ vis.Visit(body);
+ for (var tt = trg; tt != null; tt = tt.Next) {
+ tt.Tr.Iter(ee => vis.Visit(ee));
+ }
+
+ var args = new List<Bpl.Variable>();
+ Bpl.Expr typeAntecedent = Bpl.Expr.True;
+ foreach (var pair in varsAndAntecedents) {
+ var bv = pair.Item1;
+ var wh = pair.Item2;
+ if (vis.Names.Contains(bv.Name)) {
+ args.Add(bv);
+ if (wh != null) {
+ typeAntecedent = BplAnd(typeAntecedent, wh);
+ vis.Visit(wh); // this adds to "vis.Names" the free variables of "wh"
+ }
+ }
+ }
+ if (args.Count == 0) {
+ return body;
+ } else {
+ return new Bpl.ForallExpr(body.tok, args, trg, BplImp(typeAntecedent, body));
+ }
+ }
+ class VariableNameVisitor : Boogie.StandardVisitor
+ {
+ public readonly HashSet<string> Names = new HashSet<string>();
+ public override Expr VisitIdentifierExpr(Bpl.IdentifierExpr node) {
+ Names.Add(node.Name);
+ return base.VisitIdentifierExpr(node);
+ }
+ public override BinderExpr VisitBinderExpr(BinderExpr node) {
+ var vis = new VariableNameVisitor();
+ vis.Visit(node.Body);
+ var dummyNames = new HashSet<string>(node.Dummies.Select(v => v.Name));
+ foreach (var nm in vis.Names) {
+ if (!dummyNames.Contains(nm)) {
+ Names.Add(nm);
+ }
+ }
+ return base.VisitBinderExpr(node);
+ }
+ }
+
static Bpl.Expr BplForall(IEnumerable<Bpl.Variable> args_in, Bpl.Expr body) {
+ Contract.Requires(args_in != null);
+ Contract.Requires(body != null);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
var args = new List<Bpl.Variable>(args_in);
if (args.Count == 0) {
return body;
} else {
- return new Bpl.ForallExpr(body.tok, args, body);
+ return new Bpl.ForallExpr(body.tok, args, body); // NO_TRIGGER
}
}
// Note: if the trigger is null, makes a forall without any triggers
static Bpl.Expr BplForall(IEnumerable<Bpl.Variable> args_in, Bpl.Trigger trg, Bpl.Expr body) {
if (trg == null) {
- return BplForall(args_in, body);
+ return BplForall(args_in, body); // NO_TRIGGER
} else {
var args = new List<Bpl.Variable>(args_in);
if (args.Count == 0) {
@@ -14045,7 +14598,7 @@ namespace Microsoft.Dafny {
Contract.Requires(b != null);
Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
- if (a == Bpl.Expr.True || b == Bpl.Expr.True || b == Bpl.Expr.False) {
+ if (a == Bpl.Expr.True || b == Bpl.Expr.True) {
return b;
} else if (a == Bpl.Expr.False) {
return Bpl.Expr.True;
@@ -14077,7 +14630,7 @@ namespace Microsoft.Dafny {
/// Makes a simple trigger
static Bpl.Trigger BplTrigger(Bpl.Expr e) {
- return new Trigger(e.tok, true, new List<Bpl.Expr> { e });
+ return new Bpl.Trigger(e.tok, true, new List<Bpl.Expr> { e });
}
static Bpl.Axiom BplAxiom(Bpl.Expr e) {
diff --git a/Source/Dafny/Triggers/QuantifierSplitter.cs b/Source/Dafny/Triggers/QuantifierSplitter.cs
new file mode 100644
index 00000000..b039a402
--- /dev/null
+++ b/Source/Dafny/Triggers/QuantifierSplitter.cs
@@ -0,0 +1,138 @@
+using Microsoft.Boogie;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Dafny.Triggers {
+ class QuantifierSplitter : BottomUpVisitor {
+ /// This cache was introduced because some statements (notably calc) return the same SubExpression multiple times.
+ /// This ended up causing an inconsistent situation when the calc statement's subexpressions contained the same quantifier
+ /// twice: on the first pass that quantifier got its SplitQuantifiers generated, and on the the second pass these
+ /// split quantifiers got re-split, creating a situation where the direct children of a split quantifier were
+ /// also split quantifiers.
+ private Dictionary<QuantifierExpr, List<Expression>> splits = new Dictionary<QuantifierExpr, List<Expression>>();
+
+ private static BinaryExpr.Opcode FlipOpcode(BinaryExpr.Opcode opCode) {
+ if (opCode == BinaryExpr.Opcode.And) {
+ return BinaryExpr.Opcode.Or;
+ } else if (opCode == BinaryExpr.Opcode.Or) {
+ return BinaryExpr.Opcode.And;
+ } else {
+ throw new ArgumentException();
+ }
+ }
+
+ // NOTE: If we wanted to split quantifiers as far as possible, it would be
+ // enough to put the formulas in DNF (for foralls) or CNF (for exists).
+ // Unfortunately, this would cause ill-behaved quantifiers to produce
+ // exponentially many smaller quantifiers. Thus we only do one step of
+ // distributing, which takes care of the usual precondition case:
+ // forall x :: P(x) ==> (Q(x) && R(x))
+
+ private static UnaryOpExpr Not(Expression expr) {
+ return new UnaryOpExpr(expr.tok, UnaryOpExpr.Opcode.Not, expr) { Type = expr.Type };
+ }
+
+ private static Attributes CopyAttributes(Attributes source) {
+ if (source == null) {
+ return null;
+ } else {
+ return new Attributes(source.Name, source.Args, CopyAttributes(source.Prev));
+ }
+ }
+
+ internal static IEnumerable<Expression> SplitExpr(Expression expr, BinaryExpr.Opcode separator) {
+ expr = expr.Resolved;
+ var unary = expr as UnaryOpExpr;
+ var binary = expr as BinaryExpr;
+
+ if (unary != null && unary.Op == UnaryOpExpr.Opcode.Not) {
+ foreach (var e in SplitExpr(unary.E, FlipOpcode(separator))) { yield return Not(e); }
+ } else if (binary != null && binary.Op == separator) {
+ foreach (var e in SplitExpr(binary.E0, separator)) { yield return e; }
+ foreach (var e in SplitExpr(binary.E1, separator)) { yield return e; }
+ } else if (binary != null && binary.Op == BinaryExpr.Opcode.Imp && separator == BinaryExpr.Opcode.Or) {
+ foreach (var e in SplitExpr(Not(binary.E0), separator)) { yield return e; }
+ foreach (var e in SplitExpr(binary.E1, separator)) { yield return e; }
+ } else {
+ yield return expr;
+ }
+ }
+
+ internal static IEnumerable<Expression> SplitAndStich(BinaryExpr pair, BinaryExpr.Opcode separator) {
+ foreach (var e1 in SplitExpr(pair.E1, separator)) {
+ // Notice the token. This makes triggers/splitting-picks-the-right-tokens.dfy possible
+ yield return new BinaryExpr(e1.tok, pair.Op, pair.E0, e1) { ResolvedOp = pair.ResolvedOp, Type = pair.Type };
+ }
+ }
+
+ internal static IEnumerable<Expression> SplitQuantifier(QuantifierExpr quantifier) {
+ var body = quantifier.Term;
+ var binary = body as BinaryExpr;
+
+ if (quantifier is ForallExpr) {
+ IEnumerable<Expression> stream;
+ if (binary != null && (binary.Op == BinaryExpr.Opcode.Imp || binary.Op == BinaryExpr.Opcode.Or)) {
+ stream = SplitAndStich(binary, BinaryExpr.Opcode.And);
+ } else {
+ stream = SplitExpr(body, BinaryExpr.Opcode.And);
+ }
+ foreach (var e in stream) {
+ var tok = new NestedToken(quantifier.tok, e.tok);
+ yield return new ForallExpr(tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, e, CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type };
+ }
+ } else if (quantifier is ExistsExpr) {
+ IEnumerable<Expression> stream;
+ if (binary != null && binary.Op == BinaryExpr.Opcode.And) {
+ stream = SplitAndStich(binary, BinaryExpr.Opcode.Or);
+ } else {
+ stream = SplitExpr(body, BinaryExpr.Opcode.Or);
+ }
+ foreach (var e in stream) {
+ var tok = new NestedToken(quantifier.tok, e.tok);
+ yield return new ExistsExpr(tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, e, CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type };
+ }
+ } else {
+ yield return quantifier;
+ }
+ }
+
+ private static bool AllowsSplitting(QuantifierExpr quantifier) {
+ // allow split if attributes doesn't contains "split" or it is "split: true" and it is not an empty QuantifierExpr (boundvar.count>0)
+ bool splitAttr = true;
+ return (!Attributes.ContainsBool(quantifier.Attributes, "split", ref splitAttr) || splitAttr) && (quantifier.BoundVars.Count > 0);
+ }
+
+ protected override void VisitOneExpr(Expression expr) {
+ var quantifier = expr as QuantifierExpr;
+ if (quantifier != null) {
+ Contract.Assert(quantifier.SplitQuantifier == null);
+ if (!splits.ContainsKey(quantifier) && AllowsSplitting(quantifier)) {
+ splits[quantifier] = SplitQuantifier(quantifier).ToList();
+ }
+ }
+ }
+
+ protected override void VisitOneStmt(Statement stmt) {
+ if (stmt is ForallStmt) {
+ ForallStmt s = (ForallStmt)stmt;
+ if (s.ForallExpressions != null) {
+ foreach (Expression expr in s.ForallExpressions) {
+ VisitOneExpr(expr);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// See comments above definition of splits for reason why this method exists
+ /// </summary>
+ internal void Commit() {
+ foreach (var quantifier in splits.Keys) {
+ quantifier.SplitQuantifier = splits[quantifier];
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/Triggers/QuantifiersCollection.cs b/Source/Dafny/Triggers/QuantifiersCollection.cs
new file mode 100644
index 00000000..f72dab7f
--- /dev/null
+++ b/Source/Dafny/Triggers/QuantifiersCollection.cs
@@ -0,0 +1,211 @@
+#define QUANTIFIER_WARNINGS
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Dafny.Triggers {
+ class QuantifierWithTriggers {
+ internal QuantifierExpr quantifier;
+ internal List<TriggerTerm> CandidateTerms;
+ internal List<TriggerCandidate> Candidates;
+ internal List<TriggerCandidate> RejectedCandidates;
+
+ internal bool AllowsLoops { get { return TriggerUtils.AllowsMatchingLoops(quantifier); } }
+ internal bool CouldSuppressLoops { get; set; }
+
+ internal QuantifierWithTriggers(QuantifierExpr quantifier) {
+ this.quantifier = quantifier;
+ this.RejectedCandidates = new List<TriggerCandidate>();
+ }
+
+ internal void TrimInvalidTriggers() {
+ Contract.Requires(CandidateTerms != null);
+ Contract.Requires(Candidates != null);
+ Candidates = TriggerUtils.Filter(Candidates, tr => tr, (tr, _) => tr.MentionsAll(quantifier.BoundVars), (tr, _) => { }).ToList();
+ }
+ }
+
+ class QuantifiersCollection {
+ readonly ErrorReporter reporter;
+ readonly List<QuantifierWithTriggers> quantifiers;
+
+ internal QuantifiersCollection(IEnumerable<QuantifierExpr> quantifiers, ErrorReporter reporter) {
+ Contract.Requires(quantifiers.All(q => q.SplitQuantifier == null));
+ this.reporter = reporter;
+ this.quantifiers = quantifiers.Select(q => new QuantifierWithTriggers(q)).ToList();
+ }
+
+ internal void ComputeTriggers(TriggersCollector triggersCollector) {
+ CollectAndShareTriggers(triggersCollector);
+ TrimInvalidTriggers();
+ BuildDependenciesGraph();
+ SuppressMatchingLoops();
+ SelectTriggers();
+ }
+
+ private bool SubsetGenerationPredicate(TriggerUtils.SetOfTerms terms, TriggerTerm additionalTerm) {
+ return true; // FIXME Remove this
+ //return additionalTerm.Variables.Where(v => v is BoundVar && !terms.Any(t => t.Variables.Contains(v))).Any();
+ }
+
+ /// <summary>
+ /// Collect triggers from the body of each quantifier, and share them
+ /// between all quantifiers. This method assumes that all quantifiers
+ /// actually come from the same context, and were the result of a split that
+ /// gave them all the same variables.
+ /// </summary>
+ /// <param name="triggersCollector"></param>
+ void CollectAndShareTriggers(TriggersCollector triggersCollector) {
+ var pool = quantifiers.SelectMany(q => triggersCollector.CollectTriggers(q.quantifier));
+ var distinctPool = pool.Deduplicate(TriggerTerm.Eq);
+
+ foreach (var q in quantifiers) {
+ q.CandidateTerms = distinctPool; // The list of candidate terms is immutable
+ q.Candidates = TriggerUtils.AllNonEmptySubsets(distinctPool, SubsetGenerationPredicate, q.quantifier.BoundVars).Select(set => set.ToTriggerCandidate()).ToList();
+ }
+ }
+
+ private void TrimInvalidTriggers() {
+ foreach (var q in quantifiers) {
+ q.TrimInvalidTriggers();
+ }
+ }
+
+ void BuildDependenciesGraph() {
+ // The problem of finding matching loops between multiple-triggers is hard; it
+ // seems to require one to track exponentially-sized dependencies between parts
+ // of triggers and quantifiers. For now, we only do single-quantifier loop
+ // detection
+ }
+
+ void SuppressMatchingLoops() {
+ // NOTE: This only looks for self-loops; that is, loops involving a single
+ // quantifier.
+
+ // For a given quantifier q, we introduce a triggering relation between trigger
+ // candidates by writing t1 → t2 if instantiating q from t1 introduces a ground
+ // term that matches t2. Then, we notice that this relation is transitive, since
+ // all triggers yield the same set of terms. This means that any matching loop
+ // t1 → ... → t1 can be reduced to a self-loop t1 → t1. Detecting such
+ // self-loops is then only a matter of finding terms in the body of the
+ // quantifier that match a given trigger.
+
+ // Of course, each trigger that actually appears in the body of the quantifier
+ // yields a trivial self-loop (e.g. P(i) in [∀ i {P(i)} ⋅ P(i)]), so we
+ // ignore this type of loops. In fact, we ignore any term in the body of the
+ // quantifier that matches one of the terms of the trigger (this ensures that
+ // [∀ x {f(x), f(f(x))} ⋅ f(x) = f(f(x))] is not a loop). And we even
+ // ignore terms that almost match a trigger term, modulo a single variable
+ // (this ensures that [∀ x y {a(x, y)} ⋅ a(x, y) == a(y, x)] is not a loop).
+ // In addition, we ignore cases where the only differences between a trigger
+ // and a trigger match are places where a variable is replaced with an
+ // expression whose free variables do not intersect that of the quantifier
+ // in which that expression is found. For examples of this behavious, see
+ // triggers/literals-do-not-cause-loops.
+ // This ignoring logic is implemented by the CouldCauseLoops method.
+
+ foreach (var q in quantifiers) {
+ var looping = new List<TriggerCandidate>();
+
+ var safe = TriggerUtils.Filter(
+ q.Candidates,
+ candidate => candidate.LoopingSubterms(q.quantifier).ToList(),
+ (candidate, loopingSubterms) => !loopingSubterms.Any(),
+ (candidate, loopingSubterms) => {
+ looping.Add(candidate);
+ candidate.Annotation = "may loop with " + loopingSubterms.MapConcat(t => "\"" + Printer.ExprToString(t.OriginalExpr) + "\"", ", ");
+ }).ToList();
+
+ q.CouldSuppressLoops = safe.Count > 0;
+
+ if (!q.AllowsLoops && q.CouldSuppressLoops) {
+ q.Candidates = safe;
+ q.RejectedCandidates.AddRange(looping);
+ }
+ }
+ }
+
+ void SelectTriggers() {
+ foreach (var q in quantifiers) { //FIXME Check whether this makes verification faster
+ q.Candidates = TriggerUtils.Filter(q.Candidates,
+ candidate => q.Candidates.Where(candidate.IsStrongerThan).ToList(),
+ (candidate, weakerCandidates) => !weakerCandidates.Any(),
+ (candidate, weakerCandidates) => {
+ q.RejectedCandidates.Add(candidate);
+ candidate.Annotation = "more specific than " + String.Join(", ", weakerCandidates);
+ }).ToList();
+ }
+ }
+
+ private void CommitOne(QuantifierWithTriggers q, bool addHeader) {
+ var errorLevel = ErrorLevel.Info;
+ var msg = new StringBuilder();
+ var indent = addHeader ? " " : "";
+ bool suppressWarnings = Attributes.Contains(q.quantifier.Attributes, "nowarn");
+
+ if (!TriggerUtils.NeedsAutoTriggers(q.quantifier)) { // NOTE: split and autotriggers attributes are passed down to Boogie
+ var extraMsg = TriggerUtils.WantsAutoTriggers(q.quantifier) ? "" : " Note that {:autotriggers false} can cause instabilities. Consider using {:nowarn}, {:matchingloop} (not great either), or a manual trigger instead.";
+ msg.AppendFormat("Not generating triggers for \"{0}\".{1}", Printer.ExprToString(q.quantifier.Term), extraMsg).AppendLine();
+ } else {
+ if (addHeader) {
+ msg.AppendFormat("For expression \"{0}\":", Printer.ExprToString(q.quantifier.Term)).AppendLine();
+ }
+
+ foreach (var candidate in q.Candidates) {
+ q.quantifier.Attributes = new Attributes("trigger", candidate.Terms.Select(t => t.Expr).ToList(), q.quantifier.Attributes);
+ }
+
+ AddTriggersToMessage("Selected triggers:", q.Candidates, msg, indent);
+ AddTriggersToMessage("Rejected triggers:", q.RejectedCandidates, msg, indent, true);
+
+#if QUANTIFIER_WARNINGS
+ var WARN_TAG = DafnyOptions.O.UnicodeOutput ? "⚠ " : "/!\\ ";
+ var WARN_TAG_OVERRIDE = suppressWarnings ? "(Suppressed warning) " : WARN_TAG;
+ var WARN_LEVEL = suppressWarnings ? ErrorLevel.Info : ErrorLevel.Warning;
+ var WARN = indent + WARN_TAG_OVERRIDE;
+ if (!q.CandidateTerms.Any()) {
+ errorLevel = WARN_LEVEL;
+ msg.Append(WARN).AppendLine("No terms found to trigger on.");
+ } else if (!q.Candidates.Any()) {
+ errorLevel = WARN_LEVEL;
+ msg.Append(WARN).AppendLine("No trigger covering all quantified variables found.");
+ } else if (!q.CouldSuppressLoops && !q.AllowsLoops) {
+ errorLevel = WARN_LEVEL;
+ msg.Append(WARN).AppendLine("Suppressing loops would leave this expression without triggers.");
+ } else if (suppressWarnings) {
+ errorLevel = ErrorLevel.Warning;
+ msg.Append(indent).Append(WARN_TAG).AppendLine("There is no warning here to suppress.");
+ }
+#endif
+ }
+
+ if (msg.Length > 0) {
+ var msgStr = msg.ToString().TrimEnd("\r\n ".ToCharArray());
+ reporter.Message(MessageSource.Rewriter, errorLevel, q.quantifier.tok, msgStr);
+ }
+ }
+
+ private static void AddTriggersToMessage<T>(string header, List<T> triggers, StringBuilder msg, string indent, bool newlines = false) {
+ if (triggers.Any()) {
+ msg.Append(indent).Append(header);
+ if (triggers.Count == 1) {
+ msg.Append(" ");
+ } else if (triggers.Count > 1) {
+ msg.AppendLine().Append(indent).Append(" ");
+ }
+ var separator = newlines && triggers.Count > 1 ? Environment.NewLine + indent + " " : ", ";
+ msg.AppendLine(String.Join(separator, triggers));
+ }
+ }
+
+ internal void CommitTriggers() {
+ foreach (var q in quantifiers) {
+ CommitOne(q, quantifiers.Count > 1);
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/Triggers/QuantifiersCollector.cs b/Source/Dafny/Triggers/QuantifiersCollector.cs
new file mode 100644
index 00000000..cb2d5c6d
--- /dev/null
+++ b/Source/Dafny/Triggers/QuantifiersCollector.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Collections.ObjectModel;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Dafny.Triggers {
+ internal class QuantifierCollector : TopDownVisitor<bool> {
+ readonly ErrorReporter reporter;
+ private readonly HashSet<Expression> quantifiers = new HashSet<Expression>();
+ internal readonly HashSet<Expression> exprsInOldContext = new HashSet<Expression>();
+ internal readonly List<QuantifiersCollection> quantifierCollections = new List<QuantifiersCollection>();
+
+ public QuantifierCollector(ErrorReporter reporter) {
+ Contract.Requires(reporter != null);
+ this.reporter = reporter;
+ }
+
+ protected override bool VisitOneExpr(Expression expr, ref bool inOldContext) {
+ var quantifier = expr as QuantifierExpr;
+
+ // only consider quantifiers that are not empty (Bound.Vars.Count > 0)
+ if (quantifier != null && (quantifier.BoundVars.Count > 0) && !quantifiers.Contains(quantifier)) {
+ quantifiers.Add(quantifier);
+ if (quantifier.SplitQuantifier != null) {
+ var collection = quantifier.SplitQuantifier.Select(q => q as QuantifierExpr).Where(q => q != null);
+ quantifierCollections.Add(new QuantifiersCollection(collection, reporter));
+ quantifiers.UnionWith(quantifier.SplitQuantifier);
+ } else {
+ quantifierCollections.Add(new QuantifiersCollection(Enumerable.Repeat(quantifier, 1), reporter));
+ }
+ }
+
+ if (expr is OldExpr) {
+ inOldContext = true;
+ } else if (inOldContext) { // FIXME be more restrctive on the type of stuff that we annotate
+ exprsInOldContext.Add(expr);
+ }
+
+ return true;
+ }
+
+ protected override bool VisitOneStmt(Statement stmt, ref bool st) {
+ if (stmt is ForallStmt) {
+ ForallStmt s = (ForallStmt)stmt;
+ if (s.ForallExpressions != null) {
+ foreach (Expression expr in s.ForallExpressions) {
+ VisitOneExpr(expr, ref st);
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/Source/Dafny/Triggers/TriggerExtensions.cs b/Source/Dafny/Triggers/TriggerExtensions.cs
new file mode 100644
index 00000000..d4a822a8
--- /dev/null
+++ b/Source/Dafny/Triggers/TriggerExtensions.cs
@@ -0,0 +1,509 @@
+#define THROW_UNSUPPORTED_COMPARISONS
+
+using Microsoft.Dafny;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Dafny.Triggers {
+ internal static class DeduplicateExtension {
+ public static List<T> Deduplicate<T>(this IEnumerable<T> seq, Func<T, T, bool> eq) {
+ List<T> deduplicated = new List<T>();
+
+ foreach (var elem in seq) {
+ if (!deduplicated.Any(other => eq(elem, other))) {
+ deduplicated.Add(elem);
+ }
+ }
+
+ return deduplicated;
+ }
+ }
+
+ internal struct TriggerMatch {
+ internal Expression Expr;
+ internal Expression OriginalExpr;
+ internal Dictionary<IVariable, Expression> Bindings;
+
+ internal static bool Eq(TriggerMatch t1, TriggerMatch t2) {
+ return ExprExtensions.ExpressionEq(t1.Expr, t2.Expr);
+ }
+
+ /// <summary>
+ /// This method checks whether this match could actually cause a loop, given a set of terms participating in a trigger;
+ /// to compute an answer, we match the Expr of this match against the Exprs of each of these term, allowing for harmless
+ /// variations. If any of these tests does match, this term likely won't cause a loop.
+ /// The boundVars list is useful to determine that forall x :: P(x) == P(y+z) does not loop.
+ /// </summary>
+ internal bool CouldCauseLoops(List<TriggerTerm> terms, ISet<BoundVar> boundVars) {
+ var expr = Expr;
+ return !terms.Any(term => term.Expr.ExpressionEqModuloExpressionsNotInvolvingBoundVariables(expr, boundVars));
+ }
+ }
+
+ internal static class ExprExtensions {
+ internal static IEnumerable<Expression> AllSubExpressions(this Expression expr, bool wrapOld, bool strict) {
+ bool isOld = expr is OldExpr;
+
+ foreach (var subexpr in expr.SubExpressions) {
+ foreach (var r_subexpr in AllSubExpressions(subexpr, wrapOld, false)) {
+ yield return TriggerUtils.MaybeWrapInOld(r_subexpr, isOld);
+ }
+ }
+
+ if (expr is StmtExpr) {
+ foreach (var r_subexpr in AllSubExpressions(((StmtExpr)expr).S, wrapOld, false)) {
+ yield return TriggerUtils.MaybeWrapInOld(r_subexpr, isOld);
+ }
+ }
+
+ if (!strict) {
+ yield return expr;
+ }
+ }
+
+ internal static IEnumerable<Expression> AllSubExpressions(this Statement stmt, bool wrapOld, bool strict) {
+ foreach (var subexpr in stmt.SubExpressions) {
+ foreach (var r_subexpr in AllSubExpressions(subexpr, wrapOld, false)) {
+ yield return r_subexpr;
+ }
+ }
+
+ foreach (var substmt in stmt.SubStatements) {
+ foreach (var r_subexpr in AllSubExpressions(substmt, wrapOld, false)) {
+ yield return r_subexpr;
+ }
+ }
+ }
+
+ internal static bool ExpressionEq(this Expression expr1, Expression expr2) {
+ expr1 = expr1.Resolved;
+ expr2 = expr2.Resolved;
+
+ return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEq(e1, e2));
+ }
+
+ internal static bool ExpressionEqModuloExpressionsNotInvolvingBoundVariables(this Expression expr1, Expression expr2, ISet<BoundVar> boundVars) {
+ expr1 = expr1.Resolved;
+ expr2 = expr2.Resolved;
+
+ if (expr1 is IdentifierExpr) {
+ if (expr2 is IdentifierExpr) {
+ return true;
+ } else {
+ var freeInE2 = Translator.ComputeFreeVariables(expr2);
+ freeInE2.IntersectWith(boundVars);
+ return !freeInE2.Any();
+ }
+ }
+
+ return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions,
+ expr2.SubExpressions, (e1, e2) => ExpressionEqModuloExpressionsNotInvolvingBoundVariables(e1, e2, boundVars));
+ }
+
+ internal static bool MatchesTrigger(this Expression expr, Expression trigger, ISet<BoundVar> holes, Dictionary<IVariable, Expression> bindings) {
+ expr = expr.Resolved;
+ trigger = trigger.Resolved;
+
+ if (trigger is IdentifierExpr) {
+ var var = ((IdentifierExpr)trigger).Var;
+
+ if (holes.Contains(var)) {
+ Expression existing_binding = null;
+ if (bindings.TryGetValue(var, out existing_binding)) {
+ return ExpressionEq(expr, existing_binding);
+ } else {
+ bindings[var] = expr;
+ return true;
+ }
+ }
+ }
+
+ return ShallowEq_Top(expr, trigger) && TriggerUtils.SameLists(expr.SubExpressions, trigger.SubExpressions, (e1, e2) => MatchesTrigger(e1, e2, holes, bindings));
+ }
+
+ private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, IEnumerable<BoundVar> holes, Expression originalExpr) {
+ var bindings = new Dictionary<IVariable, Expression>();
+ if (expr.MatchesTrigger(trigger, new HashSet<BoundVar>(holes), bindings)) {
+ return new TriggerMatch { Expr = expr, OriginalExpr = originalExpr ?? expr, Bindings = bindings };
+ } else {
+ return null;
+ }
+ }
+
+ internal static IEnumerable<TriggerMatch> SubexpressionsMatchingTrigger(this QuantifierExpr quantifier, Expression trigger) {
+ return quantifier.AllSubExpressions(true, true)
+ .Select(e => TriggerUtils.PrepareExprForInclusionInTrigger(e).MatchAgainst(trigger, quantifier.BoundVars, e))
+ .Where(e => e.HasValue).Select(e => e.Value);
+ }
+
+ private static bool ShallowSameAttributes(Attributes attributes1, Attributes attributes2) {
+ return TriggerUtils.SameLists(attributes1.AsEnumerable(), attributes2.AsEnumerable(), ShallowSameSingleAttribute);
+ }
+
+ private static bool ShallowSameSingleAttribute(Attributes arg1, Attributes arg2) {
+ return arg1.Name == arg2.Name;
+ }
+
+ private static bool SameBoundVar(IVariable arg1, IVariable arg2) {
+ return arg1 == arg2 ||
+ (arg1.Name == arg2.Name &&
+ arg1.CompileName == arg2.CompileName &&
+ arg1.DisplayName == arg2.DisplayName &&
+ arg1.UniqueName == arg2.UniqueName &&
+ arg1.IsGhost == arg2.IsGhost &&
+ arg1.IsMutable == arg2.IsMutable &&
+ ((arg1.Type == null && arg2.Type == null) || arg1.Type.Equals(arg2.Type)));
+ }
+
+ /// <summary>
+ /// Compares two abstract syntax expressions, looking only at their direct members. Subexpressions and substatements are not compared.
+ /// </summary>
+ /// <returns></returns>
+ internal static bool ShallowEq_Top(Expression expr1, Expression expr2) {
+ Contract.Requires(expr1 != null);
+ Contract.Requires(expr2 != null);
+
+ // We never compare concrete expressions
+ Contract.Requires(!(expr1 is ConcreteSyntaxExpression));
+ Contract.Requires(!(expr2 is ConcreteSyntaxExpression));
+
+ // CPC: Hey future editor: the following block of code is auto-generated. Just add your own cases at the end.
+ // This could be a visitor pattern, except I need to visit a pair of nodes.
+ // It could also be implemented in each individual class. I'd have a slight preference for that.
+ // This really just wants to use double dispatch.
+ if (expr1 is UnboxingCastExpr && expr2 is UnboxingCastExpr) {
+ return ShallowEq((UnboxingCastExpr)expr1, (UnboxingCastExpr)expr2);
+ } else if (expr1 is BoxingCastExpr && expr2 is BoxingCastExpr) {
+ return ShallowEq((BoxingCastExpr)expr1, (BoxingCastExpr)expr2);
+ } else if (expr1 is MatchExpr && expr2 is MatchExpr) {
+ return ShallowEq((MatchExpr)expr1, (MatchExpr)expr2);
+ } else if (expr1 is ITEExpr && expr2 is ITEExpr) {
+ return ShallowEq((ITEExpr)expr1, (ITEExpr)expr2);
+ } else if (expr1 is StmtExpr && expr2 is StmtExpr) {
+ return ShallowEq((StmtExpr)expr1, (StmtExpr)expr2);
+ } else if (expr1 is WildcardExpr && expr2 is WildcardExpr) {
+ return ShallowEq((WildcardExpr)expr1, (WildcardExpr)expr2);
+ } else if (expr1 is ComprehensionExpr && expr2 is ComprehensionExpr) {
+ return ShallowEq((ComprehensionExpr)expr1, (ComprehensionExpr)expr2);
+ } else if (expr1 is NamedExpr && expr2 is NamedExpr) {
+ return ShallowEq((NamedExpr)expr1, (NamedExpr)expr2);
+ } else if (expr1 is LetExpr && expr2 is LetExpr) {
+ return ShallowEq((LetExpr)expr1, (LetExpr)expr2);
+ } else if (expr1 is TernaryExpr && expr2 is TernaryExpr) {
+ return ShallowEq((TernaryExpr)expr1, (TernaryExpr)expr2);
+ } else if (expr1 is BinaryExpr && expr2 is BinaryExpr) {
+ return ShallowEq((BinaryExpr)expr1, (BinaryExpr)expr2);
+ } else if (expr1 is UnaryExpr && expr2 is UnaryExpr) {
+ return ShallowEq((UnaryExpr)expr1, (UnaryExpr)expr2);
+ } else if (expr1 is MultiSetFormingExpr && expr2 is MultiSetFormingExpr) {
+ return ShallowEq((MultiSetFormingExpr)expr1, (MultiSetFormingExpr)expr2);
+ } else if (expr1 is OldExpr && expr2 is OldExpr) {
+ return ShallowEq((OldExpr)expr1, (OldExpr)expr2);
+ } else if (expr1 is FunctionCallExpr && expr2 is FunctionCallExpr) {
+ return ShallowEq((FunctionCallExpr)expr1, (FunctionCallExpr)expr2);
+ } else if (expr1 is ApplyExpr && expr2 is ApplyExpr) {
+ return ShallowEq((ApplyExpr)expr1, (ApplyExpr)expr2);
+ } else if (expr1 is SeqUpdateExpr && expr2 is SeqUpdateExpr) {
+ return ShallowEq((SeqUpdateExpr)expr1, (SeqUpdateExpr)expr2);
+ } else if (expr1 is MultiSelectExpr && expr2 is MultiSelectExpr) {
+ return ShallowEq((MultiSelectExpr)expr1, (MultiSelectExpr)expr2);
+ } else if (expr1 is SeqSelectExpr && expr2 is SeqSelectExpr) {
+ return ShallowEq((SeqSelectExpr)expr1, (SeqSelectExpr)expr2);
+ } else if (expr1 is MemberSelectExpr && expr2 is MemberSelectExpr) {
+ return ShallowEq((MemberSelectExpr)expr1, (MemberSelectExpr)expr2);
+ } else if (expr1 is MapDisplayExpr && expr2 is MapDisplayExpr) { //Note: MapDisplayExpr is not a DisplayExpression
+ return ShallowEq((MapDisplayExpr)expr1, (MapDisplayExpr)expr2);
+ } else if (expr1 is DisplayExpression && expr2 is DisplayExpression) {
+ return ShallowEq((DisplayExpression)expr1, (DisplayExpression)expr2);
+ } else if (expr1 is IdentifierExpr && expr2 is IdentifierExpr) {
+ return ShallowEq((IdentifierExpr)expr1, (IdentifierExpr)expr2);
+ } else if (expr1 is ThisExpr && expr2 is ThisExpr) {
+ return ShallowEq((ThisExpr)expr1, (ThisExpr)expr2);
+ } else if (expr1 is DatatypeValue && expr2 is DatatypeValue) {
+ return ShallowEq((DatatypeValue)expr1, (DatatypeValue)expr2);
+ } else if (expr1 is LiteralExpr && expr2 is LiteralExpr) {
+ return ShallowEq((LiteralExpr)expr1, (LiteralExpr)expr2);
+ } else {
+ // If this assertion fail, then a new abstract AST node was probably introduced but not registered here.
+ Contract.Assert(expr1.GetType() != expr2.GetType());
+ return false;
+ }
+ }
+
+ private static bool ShallowEq(UnboxingCastExpr expr1, UnboxingCastExpr expr2) {
+ Contract.Requires(false);
+ throw new InvalidOperationException();
+ }
+
+ private static bool ShallowEq(BoxingCastExpr expr1, BoxingCastExpr expr2) {
+ return expr1.FromType == expr2.FromType &&
+ expr1.ToType == expr2.ToType;
+ }
+
+ private static bool ShallowEq(MatchExpr expr1, MatchExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(ITEExpr expr1, ITEExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(StmtExpr expr1, StmtExpr expr2) {
+#if THROW_UNSUPPORTED_COMPARISONS
+ Contract.Assume(false); // This kind of expression never appears in a trigger
+ throw new NotImplementedException();
+#else
+ return expr1.S == expr2.S;
+#endif
+ }
+
+ private static bool ShallowEq(WildcardExpr expr1, WildcardExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(LambdaExpr expr1, LambdaExpr expr2) {
+#if THROW_UNSUPPORTED_COMPARISONS
+ Contract.Assume(false); // This kind of expression never appears in a trigger
+ throw new NotImplementedException();
+#else
+ return false;
+#endif
+ }
+
+ private static bool ShallowEq(MapComprehension expr1, MapComprehension expr2) {
+ return expr1.Finite == expr2.Finite;
+ }
+
+ private static bool ShallowEq(SetComprehension expr1, SetComprehension expr2) {
+ return expr1.TermIsImplicit == expr2.TermIsImplicit && //TODO
+ expr1.Finite == expr2.Finite;
+ }
+
+ private static bool ShallowEq(ExistsExpr expr1, ExistsExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(ForallExpr expr1, ForallExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) {
+ if (!TriggerUtils.SameNullity(expr1.SplitQuantifier, expr2.SplitQuantifier)) {
+ return false;
+ }
+
+ if (expr1.SplitQuantifier != null && expr2.SplitQuantifier != null) {
+ return ShallowEq_Top(expr1.SplitQuantifierExpression, expr2.SplitQuantifierExpression);
+ }
+
+ if (expr1.TypeArgs.Count != expr2.TypeArgs.Count ||
+ !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) {
+ return false;
+ }
+
+ if (expr1 is ExistsExpr && expr2 is ExistsExpr) {
+ return ShallowEq((ExistsExpr)expr1, (ExistsExpr)expr2);
+ } else if (expr1 is ForallExpr && expr2 is ForallExpr) {
+ return ShallowEq((ForallExpr)expr1, (ForallExpr)expr2);
+ } else {
+ return false;
+ }
+ }
+
+ private static bool ShallowEq(ComprehensionExpr expr1, ComprehensionExpr expr2) {
+ if (!TriggerUtils.SameLists(expr1.BoundVars, expr2.BoundVars, SameBoundVar) ||
+ !ShallowSameAttributes(expr1.Attributes, expr2.Attributes) ||
+ // Filled in during resolution: !SameLists(expr1.Bounds, expr2.Bounds, ReferenceCompare) ||
+ // !SameLists(expr1.MissingBounds, expr2.MissingBounds, SameBoundVar) ||
+ !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) { //TODO Check
+ return false;
+ }
+
+ if (expr1 is LambdaExpr && expr2 is LambdaExpr) {
+ return ShallowEq((LambdaExpr)expr1, (LambdaExpr)expr2);
+ } else if (expr1 is MapComprehension && expr2 is MapComprehension) {
+ return ShallowEq((MapComprehension)expr1, (MapComprehension)expr2);
+ } else if (expr1 is SetComprehension && expr2 is SetComprehension) {
+ return ShallowEq((SetComprehension)expr1, (SetComprehension)expr2);
+ } else if (expr1 is QuantifierExpr && expr2 is QuantifierExpr) {
+ return ShallowEq((QuantifierExpr)expr1, (QuantifierExpr)expr2);
+ } else {
+ return false; // ComprehensionExpr is abstract
+ }
+ }
+
+ private static bool ShallowEq(NamedExpr expr1, NamedExpr expr2) {
+ return expr1.Name == expr2.Name &&
+ TriggerUtils.SameNullity(expr1.Contract, expr2.Contract);
+ }
+
+ private static bool ShallowEq(LetExpr expr1, LetExpr expr2) {
+ return expr1.Exact == expr2.Exact &&
+ ShallowSameAttributes(expr1.Attributes, expr2.Attributes);
+ }
+
+ private static bool ShallowEq(TernaryExpr expr1, TernaryExpr expr2) {
+ return expr1.Op == expr2.Op;
+ }
+
+ private static bool ShallowEq(BinaryExpr expr1, BinaryExpr expr2) {
+ Contract.Requires(expr1.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined);
+ Contract.Requires(expr2.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined);
+ return expr1.ResolvedOp == expr2.ResolvedOp;
+ }
+
+ private static bool ShallowEq(ConversionExpr expr1, ConversionExpr expr2) {
+ return expr1.Type == expr2.Type; //TODO equality on types?
+ }
+
+ private static bool ShallowEq(UnaryOpExpr expr1, UnaryOpExpr expr2) {
+ return expr1.Op == expr2.Op;
+ }
+
+ private static bool ShallowEq(UnaryExpr expr1, UnaryExpr expr2) {
+ if (expr1 is ConversionExpr && expr2 is ConversionExpr) {
+ return ShallowEq((ConversionExpr)expr1, (ConversionExpr)expr2);
+ } else if (expr1 is UnaryOpExpr && expr2 is UnaryOpExpr) {
+ return ShallowEq((UnaryOpExpr)expr1, (UnaryOpExpr)expr2);
+ } else {
+ return false; // UnaryExpr is abstract
+ }
+ }
+
+ private static bool ShallowEq(MultiSetFormingExpr expr1, MultiSetFormingExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(OldExpr expr1, OldExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(FunctionCallExpr expr1, FunctionCallExpr expr2) {
+ return expr1.Name == expr2.Name &&
+ expr1.CoCall == expr2.CoCall && //TODO
+ expr1.Function == expr2.Function; // TODO TypeArgumentSubstitutions?
+ }
+
+ private static bool ShallowEq(ApplyExpr expr1, ApplyExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(SeqUpdateExpr expr1, SeqUpdateExpr expr2) {
+ Contract.Requires(expr1.ResolvedUpdateExpr != null && expr2.ResolvedUpdateExpr != null);
+ return true;
+ }
+
+ private static bool ShallowEq(MultiSelectExpr expr1, MultiSelectExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(SeqSelectExpr expr1, SeqSelectExpr expr2) {
+ return expr1.SelectOne == expr2.SelectOne &&
+ TriggerUtils.SameNullity(expr1.Seq, expr2.Seq) &&
+ TriggerUtils.SameNullity(expr1.E0, expr2.E0) &&
+ TriggerUtils.SameNullity(expr1.E1, expr2.E1);
+ }
+
+ private static bool ShallowEq(MemberSelectExpr expr1, MemberSelectExpr expr2) {
+ return expr1.MemberName == expr2.MemberName &&
+ expr1.Member == expr2.Member &&
+ TriggerUtils.SameLists(expr1.TypeApplication, expr2.TypeApplication, Microsoft.Dafny.Type.Equals);
+ }
+
+ private static bool ShallowEq(SeqDisplayExpr expr1, SeqDisplayExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(MapDisplayExpr expr1, MapDisplayExpr expr2) {
+ return expr1.Finite == expr2.Finite;
+ }
+
+ private static bool ShallowEq(MultiSetDisplayExpr expr1, MultiSetDisplayExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(SetDisplayExpr expr1, SetDisplayExpr expr2) {
+ return expr1.Finite == expr2.Finite;
+ }
+
+ private static bool ShallowEq(DisplayExpression expr1, DisplayExpression expr2) {
+ if (expr1 is SeqDisplayExpr && expr2 is SeqDisplayExpr) {
+ return ShallowEq((SeqDisplayExpr)expr1, (SeqDisplayExpr)expr2);
+ } else if (expr1 is MultiSetDisplayExpr && expr2 is MultiSetDisplayExpr) {
+ return ShallowEq((MultiSetDisplayExpr)expr1, (MultiSetDisplayExpr)expr2);
+ } else if (expr1 is SetDisplayExpr && expr2 is SetDisplayExpr) {
+ return ShallowEq((SetDisplayExpr)expr1, (SetDisplayExpr)expr2);
+ } else {
+ return false;
+ }
+ }
+
+ private static bool ShallowEq(AutoGhostIdentifierExpr expr1, AutoGhostIdentifierExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(IdentifierExpr expr1, IdentifierExpr expr2) {
+ if (expr1.Name != expr2.Name ||
+ expr1.Var != expr2.Var) {
+ return false;
+ }
+
+ if (expr1 is AutoGhostIdentifierExpr && expr2 is AutoGhostIdentifierExpr) {
+ return ShallowEq((AutoGhostIdentifierExpr)expr1, (AutoGhostIdentifierExpr)expr2);
+ } else {
+ return true;
+ }
+ }
+
+ private static bool ShallowEq(ImplicitThisExpr expr1, ImplicitThisExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(ThisExpr expr1, ThisExpr expr2) {
+ if (expr1 is ImplicitThisExpr && expr2 is ImplicitThisExpr) {
+ return ShallowEq((ImplicitThisExpr)expr1, (ImplicitThisExpr)expr2);
+ } else {
+ return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract
+ }
+ }
+
+ private static bool ShallowEq(DatatypeValue expr1, DatatypeValue expr2) {
+ return // Implied by Ctor equality: expr1.DatatypeName == expr2.DatatypeName &&
+ // Implied by Ctor equality: expr1.MemberName == expr2.MemberName &&
+ expr1.Ctor == expr2.Ctor &&
+ // Contextual information: expr1.IsCoCall == expr2.IsCoCall &&
+ TriggerUtils.SameLists(expr1.InferredTypeArgs, expr2.InferredTypeArgs, Microsoft.Dafny.Type.Equals);
+ }
+
+ private static bool ShallowEq(StringLiteralExpr expr1, StringLiteralExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(CharLiteralExpr expr1, CharLiteralExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(StaticReceiverExpr expr1, StaticReceiverExpr expr2) {
+ return true;
+ }
+
+ private static bool ShallowEq(LiteralExpr expr1, LiteralExpr expr2) {
+ if (!TriggerUtils.SameNullity(expr1.Value, expr2.Value) || (expr1.Value != null && !expr1.Value.Equals(expr2.Value))) {
+ return false;
+ }
+
+ if (expr1 is StringLiteralExpr && expr2 is StringLiteralExpr) {
+ return ShallowEq((StringLiteralExpr)expr1, (StringLiteralExpr)expr2);
+ } else if (expr1 is CharLiteralExpr && expr2 is CharLiteralExpr) {
+ return ShallowEq((CharLiteralExpr)expr1, (CharLiteralExpr)expr2);
+ } else if (expr1 is StaticReceiverExpr && expr2 is StaticReceiverExpr) {
+ return ShallowEq((StaticReceiverExpr)expr1, (StaticReceiverExpr)expr2);
+ } else {
+ return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/Triggers/TriggerUtils.cs b/Source/Dafny/Triggers/TriggerUtils.cs
new file mode 100644
index 00000000..c16a3e44
--- /dev/null
+++ b/Source/Dafny/Triggers/TriggerUtils.cs
@@ -0,0 +1,265 @@
+#define DEBUG_AUTO_TRIGGERS
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Dafny.Triggers {
+ class TriggerUtils {
+ internal static List<T> CopyAndAdd<T>(List<T> seq, T elem) {
+ var copy = new List<T>(seq);
+ copy.Add(elem);
+ return copy;
+ }
+
+ internal class SetOfTerms {
+ internal bool IsRedundant { get; private set; }
+ internal List<TriggerTerm> Terms { get; set; }
+
+ private ISet<BoundVar> variables;
+ private Dictionary<BoundVar, TriggerTerm> termOwningAUniqueVar;
+ private Dictionary<TriggerTerm, ISet<BoundVar>> uniqueVarsOwnedByATerm;
+
+ public int Count { get { return Terms.Count; } }
+
+ private SetOfTerms() { }
+
+ internal TriggerCandidate ToTriggerCandidate() {
+ return new TriggerCandidate(Terms);
+ }
+
+ internal static SetOfTerms Empty() {
+ var newSet = new SetOfTerms();
+ newSet.IsRedundant = false;
+ newSet.Terms = new List<TriggerTerm>();
+ newSet.variables = new HashSet<BoundVar>();
+ newSet.termOwningAUniqueVar = new Dictionary<BoundVar, TriggerTerm>();
+ newSet.uniqueVarsOwnedByATerm = new Dictionary<TriggerTerm, ISet<BoundVar>>();
+ return newSet;
+ }
+
+ /// <summary>
+ /// Simple formulas like [P0(i) && P1(i) && P2(i) && P3(i) && P4(i)] yield very
+ /// large numbers of multi-triggers, most of which are useless. As it copies its
+ /// argument, this method updates various datastructures that allow it to
+ /// efficiently track ownership relations between formulae and bound variables,
+ /// and sets the IsRedundant flag of the returned set, allowing the caller to
+ /// discard that set of terms, and the ones that would have been built on top of
+ /// it, thus ensuring that the only sets of terms produced in the end are sets
+ /// of terms in which each element contributes (owns) at least one variable.
+ ///
+ /// Note that this is trickier than just checking every term for new variables;
+ /// indeed, a new term that does bring new variables in can make an existing
+ /// term redundant (see redundancy-detection-does-its-job-properly.dfy).
+ /// </summary>
+ internal SetOfTerms CopyWithAdd(TriggerTerm term, ISet<BoundVar> relevantVariables) {
+ var copy = new SetOfTerms();
+ copy.Terms = new List<TriggerTerm>(Terms);
+ copy.variables = new HashSet<BoundVar>(variables);
+ copy.termOwningAUniqueVar = new Dictionary<BoundVar, TriggerTerm>(termOwningAUniqueVar);
+ copy.uniqueVarsOwnedByATerm = new Dictionary<TriggerTerm, ISet<BoundVar>>(uniqueVarsOwnedByATerm);
+
+ copy.Terms.Add(term);
+
+ var varsInNewTerm = new HashSet<BoundVar>(term.BoundVars);
+ varsInNewTerm.IntersectWith(relevantVariables);
+
+ var ownedByNewTerm = new HashSet<BoundVar>();
+
+ // Check #0: does this term bring anything new?
+ copy.IsRedundant = IsRedundant || varsInNewTerm.All(bv => copy.variables.Contains(bv));
+ copy.variables.UnionWith(varsInNewTerm);
+
+ // Check #1: does this term claiming ownership of all its variables cause another term to become useless?
+ foreach (var v in varsInNewTerm) {
+ TriggerTerm originalOwner;
+ if (copy.termOwningAUniqueVar.TryGetValue(v, out originalOwner)) {
+ var alsoOwnedByOriginalOwner = copy.uniqueVarsOwnedByATerm[originalOwner];
+ alsoOwnedByOriginalOwner.Remove(v);
+ if (!alsoOwnedByOriginalOwner.Any()) {
+ copy.IsRedundant = true;
+ }
+ } else {
+ ownedByNewTerm.Add(v);
+ copy.termOwningAUniqueVar[v] = term;
+ }
+ }
+
+ // Actually claim ownership
+ copy.uniqueVarsOwnedByATerm[term] = ownedByNewTerm;
+
+ return copy;
+ }
+ }
+
+ internal static IEnumerable<SetOfTerms> AllSubsets(IList<TriggerTerm> source, Func<SetOfTerms, TriggerTerm, bool> predicate, int offset, ISet<BoundVar> relevantVariables) {
+ if (offset >= source.Count) {
+ yield return SetOfTerms.Empty();
+ yield break;
+ }
+
+ foreach (var subset in AllSubsets(source, predicate, offset + 1, relevantVariables)) {
+ var newSet = subset.CopyWithAdd(source[offset], relevantVariables);
+ if (!newSet.IsRedundant && predicate(subset, source[offset])) { // Fixme remove the predicate?
+ yield return newSet;
+ }
+ yield return subset;
+ }
+ }
+
+ internal static IEnumerable<SetOfTerms> AllNonEmptySubsets(IList<TriggerTerm> source, Func<SetOfTerms, TriggerTerm, bool> predicate, IEnumerable<BoundVar> relevantVariables) {
+ foreach (var subset in AllSubsets(source, predicate, 0, new HashSet<BoundVar>(relevantVariables))) {
+ if (subset.Count > 0) {
+ yield return subset;
+ }
+ }
+ }
+
+ internal static List<T> MergeAlterFirst<T>(List<T> a, List<T> b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ a.AddRange(b);
+ return a;
+ }
+
+ internal static ISet<T> MergeAlterFirst<T>(ISet<T> a, ISet<T> b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ a.UnionWith(b);
+ return a;
+ }
+
+ internal static bool SameLists<T>(IEnumerable<T> list1, IEnumerable<T> list2, Func<T, T, bool> comparer) {
+ if (ReferenceEquals(list1, list2)) {
+ return true;
+ } else if ((list1 == null) != (list2 == null)) {
+ return false;
+ }
+
+ var it1 = list1.GetEnumerator();
+ var it2 = list2.GetEnumerator();
+ bool it1_has, it2_has;
+ bool acc = true;
+
+ do {
+ it1_has = it1.MoveNext();
+ it2_has = it2.MoveNext();
+
+ if (it1_has == true && it2_has == true) {
+ acc = acc && comparer(it1.Current, it2.Current);
+ }
+ } while (it1_has && it2_has);
+
+ return it1_has == it2_has && acc;
+ }
+
+ internal static IEnumerable<T> Filter<T, U>(IEnumerable<T> elements, Func<T, U> Converter, Func<T, U, bool> predicate, Action<T, U> reject) {
+ var positive = new List<T>();
+ foreach (var elem in elements) {
+ var conv = Converter(elem);
+ if (predicate(elem, conv)) {
+ yield return elem;
+ } else {
+ reject(elem, conv);
+ }
+ }
+ }
+
+ internal static bool SameNullity<T>(T x1, T x2) where T : class {
+ return (x1 == null) == (x2 == null);
+ }
+
+ internal string JoinStringsWithHeader(string header, IEnumerable<string> lines) {
+ return header + String.Join(Environment.NewLine + new String(' ', header.Length), lines);
+ }
+
+ [Conditional("DEBUG_AUTO_TRIGGERS")]
+ internal static void DebugTriggers(string format, params object[] more) {
+ Console.Error.WriteLine(format, more);
+ }
+
+ internal static bool AllowsMatchingLoops(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ // This is different from nowarn: it won't remove loops at all, even if another trigger is available.
+ return Attributes.Contains(quantifier.Attributes, "matchingloop");
+ }
+
+ internal static bool WantsAutoTriggers(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ bool wantsAutoTriggers = true;
+ return !Attributes.ContainsBool(quantifier.Attributes, "autotriggers", ref wantsAutoTriggers) || wantsAutoTriggers;
+ }
+
+ internal static bool NeedsAutoTriggers(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ return !Attributes.Contains(quantifier.Attributes, "trigger") && WantsAutoTriggers(quantifier);
+ }
+
+ internal static BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) {
+ switch (opcode) {
+ case BinaryExpr.ResolvedOpcode.NotInMap:
+ return BinaryExpr.ResolvedOpcode.InMap;
+ case BinaryExpr.ResolvedOpcode.NotInSet:
+ return BinaryExpr.ResolvedOpcode.InSet;
+ case BinaryExpr.ResolvedOpcode.NotInSeq:
+ return BinaryExpr.ResolvedOpcode.InSeq;
+ case BinaryExpr.ResolvedOpcode.NotInMultiSet:
+ return BinaryExpr.ResolvedOpcode.InMultiSet;
+ }
+
+ Contract.Assert(false);
+ throw new ArgumentException();
+ }
+
+ internal static Expression PrepareExprForInclusionInTrigger(Expression expr, out bool isKiller) {
+ isKiller = false;
+
+ var ret = expr;
+ if (ret is BinaryExpr) {
+ ret = PrepareInMultisetForInclusionInTrigger(PrepareNotInForInclusionInTrigger((BinaryExpr)ret), ref isKiller);
+ }
+
+ return ret;
+ }
+
+ private static BinaryExpr PrepareNotInForInclusionInTrigger(BinaryExpr bexpr) {
+ if (bexpr.Op == BinaryExpr.Opcode.NotIn) {
+ var new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1);
+ new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp);
+ new_expr.Type = bexpr.Type;
+ return new_expr;
+ } else {
+ return bexpr;
+ }
+ }
+
+ private static Expression PrepareInMultisetForInclusionInTrigger(BinaryExpr bexpr, ref bool isKiller) {
+ if (bexpr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) {
+ var new_expr = new SeqSelectExpr(bexpr.tok, true, bexpr.E1, bexpr.E0, null);
+ new_expr.Type = bexpr.Type;
+ isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer
+ return new_expr;
+ } else {
+ return bexpr;
+ }
+ }
+
+ internal static Expression PrepareExprForInclusionInTrigger(Expression expr) {
+ bool _;
+ return PrepareExprForInclusionInTrigger(expr, out _);
+ }
+
+ internal static Expression MaybeWrapInOld(Expression expr, bool wrap) {
+ if (wrap && !(expr is NameSegment) && !(expr is IdentifierExpr)) {
+ var newExpr = new OldExpr(expr.tok, expr);
+ newExpr.Type = expr.Type;
+ return newExpr;
+ } else {
+ return expr;
+ }
+ }
+ }
+}
diff --git a/Source/Dafny/Triggers/TriggersCollector.cs b/Source/Dafny/Triggers/TriggersCollector.cs
new file mode 100644
index 00000000..4204cc29
--- /dev/null
+++ b/Source/Dafny/Triggers/TriggersCollector.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics.Contracts;
+using System.Diagnostics;
+
+namespace Microsoft.Dafny.Triggers {
+ class TriggerTerm {
+ internal Expression Expr { get; set; }
+ internal Expression OriginalExpr { get; set; }
+ internal ISet<IVariable> Variables { get; set; }
+ internal IEnumerable<BoundVar> BoundVars {
+ get {
+ return Variables.Select(v => v as BoundVar).Where(v => v != null);
+ }
+ }
+
+ public override string ToString() {
+ return Printer.ExprToString(Expr);
+ // NOTE: Using OriginalExpr here could cause some confusion:
+ // for example, {a !in b} is a binary expression, yielding
+ // trigger {a in b}. Saying the trigger is a !in b would be
+ // rather misleading.
+ }
+
+ internal enum TermComparison {
+ SameStrength = 0, Stronger = 1, NotStronger = -1
+ }
+
+ internal TermComparison CompareTo(TriggerTerm other) {
+ if (this == other) {
+ return TermComparison.SameStrength;
+ } else if (Expr.AllSubExpressions(true, true).Any(other.Expr.ExpressionEq)) {
+ return TermComparison.Stronger;
+ } else {
+ return TermComparison.NotStronger;
+ }
+ }
+
+ internal static bool Eq(TriggerTerm t1, TriggerTerm t2) {
+ return ExprExtensions.ExpressionEq(t1.Expr, t2.Expr);
+ }
+ }
+
+ class TriggerCandidate {
+ internal List<TriggerTerm> Terms { get; set; }
+ internal string Annotation { get; set; }
+
+ internal TriggerCandidate(List<TriggerTerm> terms) {
+ this.Terms = terms;
+ }
+
+ public TriggerCandidate(TriggerCandidate candidate) {
+ this.Terms = candidate.Terms;
+ }
+
+ internal bool MentionsAll(List<BoundVar> vars) {
+ return vars.All(x => Terms.Any(term => term.Variables.Contains(x)));
+ }
+
+ internal string Repr { get { return String.Join(", ", Terms); } }
+
+ public override string ToString() {
+ return "{" + Repr + "}" + (String.IsNullOrWhiteSpace(Annotation) ? "" : " (" + Annotation + ")");
+ }
+
+ internal IEnumerable<TriggerMatch> LoopingSubterms(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ var matchingSubterms = this.MatchingSubterms(quantifier);
+ var boundVars = new HashSet<BoundVar>(quantifier.BoundVars);
+ return matchingSubterms.Where(tm => tm.CouldCauseLoops(Terms, boundVars));
+ }
+
+ internal List<TriggerMatch> MatchingSubterms(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ return Terms.SelectMany(term => quantifier.SubexpressionsMatchingTrigger(term.Expr)).Deduplicate(TriggerMatch.Eq);
+ }
+
+ internal bool IsStrongerThan(TriggerCandidate that) {
+ if (this == that) {
+ return false;
+ }
+
+ var hasStrictlyStrongerTerm = false;
+ foreach (var t in Terms) {
+ var comparison = that.Terms.Select(t.CompareTo).Max();
+
+ // All terms of `this` must be at least as strong as a term of `that`
+ if (comparison == TriggerTerm.TermComparison.NotStronger) { return false; }
+
+ // Did we find a strictly stronger term?
+ hasStrictlyStrongerTerm = hasStrictlyStrongerTerm || comparison == TriggerTerm.TermComparison.Stronger;
+ }
+
+ return hasStrictlyStrongerTerm;
+ }
+ }
+
+ internal class TriggerAnnotation {
+ internal bool IsTriggerKiller;
+ internal ISet<IVariable> Variables;
+ internal readonly List<TriggerTerm> PrivateTerms;
+ internal readonly List<TriggerTerm> ExportedTerms;
+
+ internal TriggerAnnotation(bool IsTriggerKiller, IEnumerable<IVariable> Variables, IEnumerable<TriggerTerm> AllTerms, IEnumerable<TriggerTerm> PrivateTerms = null) {
+ this.IsTriggerKiller = IsTriggerKiller;
+ this.Variables = new HashSet<IVariable>(Variables);
+ this.PrivateTerms = new List<TriggerTerm>(PrivateTerms == null ? Enumerable.Empty<TriggerTerm>() : PrivateTerms);
+ this.ExportedTerms = new List<TriggerTerm>(AllTerms == null ? Enumerable.Empty<TriggerTerm>() : AllTerms.Except(this.PrivateTerms));
+ }
+
+ public override string ToString() {
+ StringBuilder sb = new StringBuilder();
+ string indent = " {0}", nindent = "\n - {0}", subindent = "\n * {0}";
+
+ sb.AppendFormat(indent, IsTriggerKiller);
+
+ sb.AppendFormat(nindent, "Variables:");
+ foreach (var bv in Variables) {
+ sb.AppendFormat(subindent, bv.Name);
+ }
+
+ sb.AppendFormat(nindent, "Exported terms:");
+ foreach (var term in ExportedTerms) {
+ sb.AppendFormat(subindent, term);
+ }
+
+ if (PrivateTerms.Any()) {
+ sb.AppendFormat(nindent, "Private terms:");
+ foreach (var term in PrivateTerms) {
+ sb.AppendFormat(subindent, term);
+ }
+ }
+
+ return sb.ToString();
+ }
+ }
+
+ internal class TriggerAnnotationsCache {
+ public readonly HashSet<Expression> exprsInOldContext;
+ public readonly Dictionary<Expression, TriggerAnnotation> annotations;
+
+ /// <summary>
+ /// For certain operations, the TriggersCollector class needs to know whether
+ /// an particular expression is under an old(...) wrapper. This is in particular
+ /// true for generating trigger terms (but it is not for checking wehter something
+ /// is a trigger killer, so passing an empty set here for that case would be fine.
+ /// </summary>
+ public TriggerAnnotationsCache(HashSet<Expression> exprsInOldContext) {
+ this.exprsInOldContext = exprsInOldContext;
+ annotations = new Dictionary<Expression, TriggerAnnotation>();
+ }
+ }
+
+ internal class TriggersCollector {
+ TriggerAnnotationsCache cache;
+
+ internal TriggersCollector(HashSet<Expression> exprsInOldContext) {
+ this.cache = new TriggerAnnotationsCache(exprsInOldContext);
+ }
+
+ private T ReduceAnnotatedSubExpressions<T>(Expression expr, T seed, Func<TriggerAnnotation, T> map, Func<T, T, T> reduce) {
+ return expr.SubExpressions.Select(e => map(Annotate(e)))
+ .Aggregate(seed, (acc, e) => reduce(acc, e));
+ }
+
+ private List<TriggerTerm> CollectExportedCandidates(Expression expr) {
+ return ReduceAnnotatedSubExpressions<List<TriggerTerm>>(expr, new List<TriggerTerm>(), a => a.ExportedTerms, TriggerUtils.MergeAlterFirst);
+ }
+
+ private ISet<IVariable> CollectVariables(Expression expr) {
+ return ReduceAnnotatedSubExpressions(expr, new HashSet<IVariable>(), a => a.Variables, TriggerUtils.MergeAlterFirst);
+ }
+
+ private bool CollectIsKiller(Expression expr) {
+ return ReduceAnnotatedSubExpressions(expr, false, a => a.IsTriggerKiller, (a, b) => a || b);
+ }
+
+ private IEnumerable<TriggerTerm> OnlyPrivateCandidates(List<TriggerTerm> terms, IEnumerable<IVariable> privateVars) {
+ return terms.Where(c => privateVars.Intersect(c.Variables).Any()); //TODO Check perf
+ }
+
+ private TriggerAnnotation Annotate(Expression expr) {
+ TriggerAnnotation cached;
+ if (cache.annotations.TryGetValue(expr, out cached)) {
+ return cached;
+ }
+
+ expr.SubExpressions.Iter(e => Annotate(e));
+
+ TriggerAnnotation annotation; // TODO: Using ApplySuffix fixes the unresolved members problem in GenericSort
+ if (expr is FunctionCallExpr ||
+ expr is SeqSelectExpr ||
+ expr is MultiSelectExpr ||
+ expr is MemberSelectExpr ||
+ expr is OldExpr ||
+ expr is ApplyExpr ||
+ expr is DisplayExpression ||
+ TranslateToFunctionCall(expr) ||
+ (expr is UnaryOpExpr && (((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Cardinality)) || // FIXME || ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Fresh doesn't work, as fresh is a pretty tricky predicate when it's not about datatypes. See translator.cs:10944
+ (expr is BinaryExpr && (((BinaryExpr)expr).Op == BinaryExpr.Opcode.NotIn || ((BinaryExpr)expr).Op == BinaryExpr.Opcode.In))) {
+ annotation = AnnotatePotentialCandidate(expr);
+ } else if (expr is QuantifierExpr) {
+ annotation = AnnotateQuantifier((QuantifierExpr)expr);
+ } else if (expr is LetExpr) {
+ annotation = AnnotateLetExpr((LetExpr)expr);
+ } else if (expr is IdentifierExpr) {
+ annotation = AnnotateIdentifier((IdentifierExpr)expr);
+ } else if (expr is ApplySuffix) {
+ annotation = AnnotateApplySuffix((ApplySuffix)expr);
+ } else if (expr is ComprehensionExpr) {
+ annotation = AnnotateComprehensionExpr((ComprehensionExpr)expr);
+ } else if (expr is ConcreteSyntaxExpression ||
+ expr is LiteralExpr ||
+ expr is OldExpr ||
+ expr is ThisExpr ||
+ expr is BoxingCastExpr ||
+ expr is DatatypeValue) {
+ annotation = AnnotateOther(expr, false);
+ } else {
+ annotation = AnnotateOther(expr, true);
+ }
+
+ TriggerUtils.DebugTriggers("{0} ({1})\n{2}", Printer.ExprToString(expr), expr.GetType(), annotation);
+ cache.annotations[expr] = annotation;
+ return annotation;
+ }
+
+ // math operations can be turned into a Boogie-level function as in the
+ // case with /noNLarith.
+ public bool TranslateToFunctionCall(Expression expr) {
+ if (!(expr is BinaryExpr)) {
+ return false;
+ }
+ BinaryExpr e = (BinaryExpr) expr;
+ bool isReal = e.E0.Type.IsNumericBased(Type.NumericPersuation.Real);
+ switch (e.ResolvedOp) {
+ case BinaryExpr.ResolvedOpcode.Lt:
+ case BinaryExpr.ResolvedOpcode.Le:
+ case BinaryExpr.ResolvedOpcode.Ge:
+ case BinaryExpr.ResolvedOpcode.Gt:
+ case BinaryExpr.ResolvedOpcode.Add:
+ case BinaryExpr.ResolvedOpcode.Sub:
+ case BinaryExpr.ResolvedOpcode.Mul:
+ case BinaryExpr.ResolvedOpcode.Div:
+ case BinaryExpr.ResolvedOpcode.Mod:
+ if (!isReal && DafnyOptions.O.DisableNLarith) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+ private TriggerAnnotation AnnotatePotentialCandidate(Expression expr) {
+ bool expr_is_killer = false;
+ var new_expr = TriggerUtils.MaybeWrapInOld(TriggerUtils.PrepareExprForInclusionInTrigger(expr, out expr_is_killer), cache.exprsInOldContext.Contains(expr));
+ var new_term = new TriggerTerm { Expr = new_expr, OriginalExpr = expr, Variables = CollectVariables(expr) };
+
+ List<TriggerTerm> collected_terms = CollectExportedCandidates(expr);
+ var children_contain_killers = CollectIsKiller(expr);
+
+ if (!children_contain_killers) {
+ // Add only if the children are not killers; the head has been cleaned up into non-killer form
+ collected_terms.Add(new_term);
+ }
+
+ // This new node is a killer if its children were killers, or if it's non-cleaned-up head is a killer
+ return new TriggerAnnotation(children_contain_killers || expr_is_killer, new_term.Variables, collected_terms);
+ }
+
+ private TriggerAnnotation AnnotateApplySuffix(ApplySuffix expr) {
+ // This is a bit tricky. A funcall node is generally meaningful as a trigger candidate,
+ // but when it's part of an ApplySuffix the function call itself may not resolve properly
+ // when the second round of resolving is done after modules are duplicated.
+ // Thus first we annotate expr and create a trigger candidate, and then we remove the
+ // candidate matching its direct subexpression if needed. Note that function calls are not the
+ // only possible child here; there can be DatatypeValue nodes, for example (see vstte2012/Combinators.dfy).
+ var annotation = AnnotatePotentialCandidate(expr);
+ // Comparing by reference is fine here. Using sets could yield a small speedup
+ annotation.ExportedTerms.RemoveAll(term => expr.SubExpressions.Contains(term.Expr));
+ return annotation;
+ }
+
+ private TriggerAnnotation AnnotateQuantifierOrLetExpr(Expression expr, IEnumerable<BoundVar> boundVars) {
+ var terms = CollectExportedCandidates(expr);
+ return new TriggerAnnotation(true, CollectVariables(expr), terms, OnlyPrivateCandidates(terms, boundVars));
+ }
+
+ private TriggerAnnotation AnnotateQuantifier(QuantifierExpr expr) {
+ return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars);
+ }
+
+ private TriggerAnnotation AnnotateLetExpr(LetExpr expr) {
+ return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars);
+ }
+
+ private TriggerAnnotation AnnotateIdentifier(IdentifierExpr expr) {
+ return new TriggerAnnotation(false, Enumerable.Repeat(expr.Var, 1), null);
+ }
+
+ private TriggerAnnotation AnnotateComprehensionExpr(ComprehensionExpr expr) {
+ var terms = CollectExportedCandidates(expr);
+ return new TriggerAnnotation(true, CollectVariables(expr), terms, OnlyPrivateCandidates(terms, expr.BoundVars));
+ }
+
+ private TriggerAnnotation AnnotateOther(Expression expr, bool isTriggerKiller) {
+ return new TriggerAnnotation(isTriggerKiller || CollectIsKiller(expr), CollectVariables(expr), CollectExportedCandidates(expr));
+ }
+
+ /// <summary>
+ /// Collect terms in the body of the subexpressions of the argument that look like quantifiers. The results of this function can contain duplicate terms.
+ /// </summary>
+ internal List<TriggerTerm> CollectTriggers(QuantifierExpr quantifier) {
+ Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier
+ // NOTE: We could check for existing trigger attributes and return that instead
+ return Annotate(quantifier).PrivateTerms;
+ }
+
+ internal bool IsTriggerKiller(Expression expr) {
+ return Annotate(expr).IsTriggerKiller;
+ }
+ }
+}
diff --git a/Source/Dafny/Util.cs b/Source/Dafny/Util.cs
index f9421659..eaf599e3 100644
--- a/Source/Dafny/Util.cs
+++ b/Source/Dafny/Util.cs
@@ -8,7 +8,7 @@ using Microsoft.Boogie;
namespace Microsoft.Dafny {
- class Util
+ public class Util
{
public static string Comma<T>(IEnumerable<T> l, Func<T, string> f) {
return Comma(",", l, f);
@@ -72,13 +72,7 @@ namespace Microsoft.Dafny {
/// </summary>
public static string RemoveUnderscores(string s) {
Contract.Requires(s != null);
- while (true) {
- var j = s.IndexOf('_');
- if (j == -1) {
- return s;
- }
- s = s.Substring(0, j) + s.Substring(j + 1);
- }
+ return s.Replace("_", "");
}
/// <summary>
@@ -175,5 +169,152 @@ namespace Microsoft.Dafny {
}
}
+ /// <summary>
+ /// Class dedicated to traversing the function call graph
+ /// </summary>
+ class FunctionCallFinder : TopDownVisitor<List<Function>> {
+ protected override bool VisitOneExpr(Expression expr, ref List<Function> calls) {
+ if (expr is FunctionCallExpr) {
+ calls.Add(((FunctionCallExpr)expr).Function);
+ }
+ return true;
+ }
+ }
+
+ static Graph<Function> BuildFunctionCallGraph(Dafny.Program program) {
+ Graph<Function> functionCallGraph = new Graph<Function>();
+ FunctionCallFinder callFinder = new FunctionCallFinder();
+
+ foreach (var module in program.Modules) {
+ foreach (var decl in module.TopLevelDecls) {
+ if (decl is ClassDecl) {
+ var c = (ClassDecl)decl;
+ foreach (var member in c.Members) {
+ if (member is Function) {
+ var f = (Function)member;
+
+ List<Function> calls = new List<Function>();
+ foreach (var e in f.Reads) { if (e != null && e.E != null) { callFinder.Visit(e.E, calls); } }
+ foreach (var e in f.Req) { if (e != null) { callFinder.Visit(e, calls); } }
+ foreach (var e in f.Ens) { if (e != null) { callFinder.Visit(e, calls); } }
+ if (f.Body != null) {
+ callFinder.Visit(f.Body, calls);
+ }
+
+ foreach (var callee in calls) {
+ functionCallGraph.AddEdge(f, callee);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return functionCallGraph;
+ }
+
+ /// <summary>
+ /// Prints the program's function call graph in a format suitable for consumption in other tools
+ /// </summary>
+ public static void PrintFunctionCallGraph(Dafny.Program program) {
+ var functionCallGraph = BuildFunctionCallGraph(program);
+
+ foreach (var vertex in functionCallGraph.GetVertices()) {
+ var func = vertex.N;
+ Console.Write("{0},{1}=", func.CompileName, func.EnclosingClass.Module.CompileName);
+ foreach (var callee in vertex.Successors) {
+ Console.Write("{0} ", callee.N.CompileName);
+ }
+ Console.Write("\n");
+ }
+ }
+
+ /// <summary>
+ /// Generic statistic counter
+ /// </summary>
+ static void IncrementStat(IDictionary<string, ulong> stats, string stat) {
+ ulong currentValue;
+ if (stats.TryGetValue(stat, out currentValue)) {
+ stats[stat] += 1;
+ } else {
+ stats.Add(stat, 1);
+ }
+ }
+
+ /// <summary>
+ /// Track the maximum value of some statistic
+ /// </summary>
+ static void UpdateMax(IDictionary<string, ulong> stats, string stat, ulong val) {
+ ulong currentValue;
+ if (stats.TryGetValue(stat, out currentValue)) {
+ if (val > currentValue) {
+ stats[stat] = val;
+ }
+ } else {
+ stats.Add(stat, val);
+ }
+ }
+
+ /// <summary>
+ /// Compute various interesting statistics about the Dafny program
+ /// </summary>
+ public static void PrintStats(Dafny.Program program) {
+ SortedDictionary<string, ulong> stats = new SortedDictionary<string, ulong>();
+
+ foreach (var module in program.Modules) {
+ IncrementStat(stats, "Modules");
+ UpdateMax(stats, "Module height (max)", (ulong)module.Height);
+
+ ulong num_scc = (ulong)module.CallGraph.TopologicallySortedComponents().Count;
+ UpdateMax(stats, "Call graph width (max)", num_scc);
+
+ foreach (var decl in module.TopLevelDecls) {
+ if (decl is DatatypeDecl) {
+ IncrementStat(stats, "Datatypes");
+ } else if (decl is ClassDecl) {
+ var c = (ClassDecl)decl;
+ if (c.Name != "_default") {
+ IncrementStat(stats, "Classes");
+ }
+
+ foreach (var member in c.Members) {
+ if (member is Function) {
+ IncrementStat(stats, "Functions (total)");
+ var f = (Function)member;
+ if (f.IsRecursive) {
+ IncrementStat(stats, "Functions recursive");
+ }
+ } else if (member is Method) {
+ IncrementStat(stats, "Methods (total)");
+ var method = (Method)member;
+ if (method.IsRecursive) {
+ IncrementStat(stats, "Methods recursive");
+ }
+ if (method.IsGhost) {
+ IncrementStat(stats, "Methods ghost");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Print out the results, with some nice formatting
+ Console.WriteLine("");
+ Console.WriteLine("Statistics");
+ Console.WriteLine("----------");
+
+ int max_key_length = 0;
+ foreach (var key in stats.Keys) {
+ if (key.Length > max_key_length) {
+ max_key_length = key.Length;
+ }
+ }
+
+ foreach (var keypair in stats) {
+ string keyString = keypair.Key.PadRight(max_key_length + 2);
+ Console.WriteLine("{0} {1,4}", keyString, keypair.Value);
+ }
+ }
}
}