From 4882523dcc2bf0c46d2cb3154ecb19bc9ea4f5cb Mon Sep 17 00:00:00 2001 From: Rustan Leino Date: Tue, 24 May 2011 21:30:57 -0700 Subject: Dafny: * fixed parsing problem with a block ending a block * replaced AssignStmt and "call" statements with UpdateStmt's * fixed some minor printing problems * changed implementation to check for ghost expressions in a pass separate from ResolveExpr To-dos: * compile and translate multi-assignments * handle non-identifier LHSs of call statements * change "var" statements in a similar way * tighten up parsing of LHSs to allow only things like SelectExpr * code and grammar clean-up to remove unused parts (e.g., "call" grammar productions and the "allowGhostFeatures" parameters) * include the commented-out precondition of TrAssignment * check in changes to the test suite --- Dafny/Compiler.cs | 7 + Dafny/Dafny.atg | 113 ++++++-- Dafny/DafnyAst.cs | 102 +++++-- Dafny/Parser.cs | 803 +++++++++++++++++++++++++++++----------------------- Dafny/Printer.cs | 26 +- Dafny/Resolver.cs | 633 +++++++++++++++++++++++++++++------------ Dafny/Scanner.cs | 131 ++++----- Dafny/Translator.cs | 9 + 8 files changed, 1157 insertions(+), 667 deletions(-) (limited to 'Dafny') diff --git a/Dafny/Compiler.cs b/Dafny/Compiler.cs index 80e597e5..86fd1688 100644 --- a/Dafny/Compiler.cs +++ b/Dafny/Compiler.cs @@ -840,6 +840,13 @@ namespace Microsoft.Dafny { Indent(indent); wr.WriteLine("}"); } + } else if (stmt is ConcreteSyntaxStatement) { + var s = (ConcreteSyntaxStatement)stmt; + // TODO: Update statements should perform multiple assignments in parallel! + foreach (var ss in s.ResolvedStatements) { + TrStmt(ss, indent); + } + } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement } diff --git a/Dafny/Dafny.atg b/Dafny/Dafny.atg index d25000ee..4b477b28 100644 --- a/Dafny/Dafny.atg +++ b/Dafny/Dafny.atg @@ -727,11 +727,6 @@ Stmt<.List/*!*/ ss.> = (. Contract.Requires(cce.NonNullElements(ss)); Statement/*!*/ s; IToken bodyStart, bodyEnd; .) - /* By first reading a sequence of block statements, we avoid problems in the generated parser, despite - the ambiguity in the grammar. See Note in ConstAtomExpression production. - */ - { BlockStmt (. ss.Add(s); .) - } ( OneStmt (. ss.Add(s); .) | VarDeclStmts ) @@ -740,15 +735,18 @@ Stmt<.List/*!*/ ss.> OneStmt = (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; IToken/*!*/ id; string label = null; s = dummyStmt; /* to please the compiler */ + IToken bodyStart, bodyEnd; .) /* This list does not contain BlockStmt, see comment above in Stmt production. */ - ( AssertStmt + ( BlockStmt + | AssertStmt | AssumeStmt | UseStmt | PrintStmt - | AssignStmt +/* | AssignStmt */ | HavocStmt | CallStmt + | "call" UpdateStmt | IfStmt | WhileStmt | MatchStmt @@ -760,11 +758,70 @@ OneStmt ] ";" (. s = new BreakStmt(x, label); .) | "return" (. x = t; .) ";" (. s = new ReturnStmt(x); .) + | UpdateStmt + ) + . + +UpdateStmt += (. List lhss = new List(); + List rhss = new List(); + Expression e; DeterminedAssignmentRhs r; + Expression lhs0; + IToken x; + .) + Lhs (. x = e.tok; .) + ( ";" (. rhss.Add(new ExprRhs(e)); .) + | (. lhss.Add(e); lhs0 = e; .) + { "," Lhs (. lhss.Add(e); .) + } + ":=" (. x = t; .) + Rhs (. rhss.Add(r); .) + { "," Rhs (. rhss.Add(r); .) + } + ";" + ) + (. s = new UpdateStmt(x, lhss, rhss); .) + . + +Rhs += (. IToken/*!*/ x, newToken; Expression/*!*/ e; + List ee = null; + Type ty = null; + CallStmt initCall = null; + List args; + r = null; // to please compiler + .) + ( "new" (. newToken = t; .) + TypeAndToken + [ "[" (. ee = new List(); .) + Expressions + "]" (. // make sure an array class with this dimensionality exists + UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true); + .) + | "." Ident + "(" (. args = new List(); .) + [ Expressions ] + ")" (. initCall = new CallStmt(x, new List(), new List(), + receiverForInitCall, x.val, args); .) + ] + (. if (ee != null) { + r = new TypeRhs(newToken, ty, ee); + } else { + r = new TypeRhs(newToken, ty, initCall); + } + .) + + /* One day, the choose expression should be treated just as a special case of a method call. */ + | "choose" (. x = t; .) + Expression (. r = new ExprRhs(new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e)); .) + + | Expression (. r = new ExprRhs(e); .) ) . AssignStmt -= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; += (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); + IToken/*!*/ x, rhsTok; Expression/*!*/ lhs; List rhs; Type ty; @@ -773,11 +830,11 @@ AssignStmt .) LhsExpr ":=" (. x = t; .) - AssignRhs + AssignRhs (. if (ty == null) { Contract.Assert(rhs != null); Contract.Assert(rhs.Count == 1); - s = new AssignStmt(x, lhs, rhs[0]); + s = new AssignStmt(x, lhs, new ExprRhs(rhs[0])); if (!allowChoose) { var r = rhs[0] as UnaryExpr; if (r != null && r.Op == UnaryExpr.Opcode.SetChoose) { @@ -785,15 +842,15 @@ AssignStmt } } } else if (rhs == null) { - s = new AssignStmt(x, lhs, ty, initCall); + s = new AssignStmt(x, lhs, new TypeRhs(rhsTok, ty, initCall)); } else { - s = new AssignStmt(x, lhs, ty, rhs); + s = new AssignStmt(x, lhs, new TypeRhs(rhsTok, ty, rhs)); } .) ";" . -AssignRhs<.out List ee, out Type ty, out CallStmt initCall, Expression receiverForInitCall.> +AssignRhs<.out IToken tok, out List ee, out Type ty, out CallStmt initCall, Expression receiverForInitCall.> /* ensures ee != null || ty != null; */ /* ensures ee != null ==> 1 <= ee.Count; */ /* ensures ty == null ==> 1 == ee.Count; */ @@ -801,8 +858,10 @@ AssignRhs<.out List ee, out Type ty, out CallStmt initCall, Expressi ee = null; ty = null; initCall = null; List args; + tok = Token.NoToken; // to please compiler .) - ( "new" TypeAndToken + ( "new" (. tok = t; .) + TypeAndToken [ "[" (. ee = new List(); .) Expressions "]" (. // make sure an array class with this dimensionality exists @@ -814,11 +873,11 @@ AssignRhs<.out List ee, out Type ty, out CallStmt initCall, Expressi ")" (. initCall = new CallStmt(x, new List(), new List(), receiverForInitCall, x.val, args); .) ] - | "choose" (. x = t; .) + | "choose" (. x = t; tok = t; .) Expression (. e = new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e); ee = new List() { e }; .) - | Expression (. ee = new List() { e }; .) + | Expression (. tok = e.tok; ee = new List() { e }; .) ) (. if (ee == null && ty == null) { ee = new List() { dummyExpr}; } .) . @@ -845,7 +904,8 @@ VarDeclStmts<.List/*!*/ ss.> . IdentTypeRhs -= (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); IToken/*!*/ id; Type/*!*/ ty; += (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); + IToken/*!*/ id, rhsTok = null; Type/*!*/ ty; List rhs = null; Type newType = null; Type optionalType = null; DeterminedAssignmentRhs optionalRhs = null; CallStmt initCall = null; @@ -854,16 +914,16 @@ IdentTypeRhs [ ":" Type (. optionalType = ty; .) ] [ ":=" - AssignRhs + AssignRhs ] (. if (newType == null && rhs != null) { Contract.Assert(rhs.Count == 1); optionalRhs = new ExprRhs(rhs[0]); } else if (newType != null) { if (rhs == null) { - optionalRhs = new TypeRhs(newType, initCall); + optionalRhs = new TypeRhs(rhsTok, newType, initCall); } else { - optionalRhs = new TypeRhs(newType, rhs); + optionalRhs = new TypeRhs(rhsTok, newType, rhs); } } else if (optionalType == null) { optionalType = new InferredTypeProxy(); @@ -1010,7 +1070,7 @@ CallStmt List lhs = new List(); List newVars = new List(); .) - "call" (. x = t; .) + "callXYZXYZ" (. x = t; .) CallStmtSubExpr [ "," /* call a,b,c,... := ... */ @@ -1244,6 +1304,17 @@ UnaryExpression ) . +Lhs += (. e = null; // to please the compiler + .) + ( DottedIdentifiersAndFunction + { Suffix } + | ConstAtomExpression + Suffix + { Suffix } + ) + . + NegOp = "!" | '\u00ac'. /* A ConstAtomExpression is never an l-value. Also, a ConstAtomExpression is never followed by diff --git a/Dafny/DafnyAst.cs b/Dafny/DafnyAst.cs index 79f20d5d..1f46d5ba 100644 --- a/Dafny/DafnyAst.cs +++ b/Dafny/DafnyAst.cs @@ -753,12 +753,14 @@ namespace Microsoft.Dafny { } public abstract class MemberDecl : Declaration { + public readonly bool IsStatic; public ClassDecl EnclosingClass; // filled in during resolution - public MemberDecl(IToken tok, string name, Attributes attributes) + public MemberDecl(IToken tok, string name, bool isStatic, Attributes attributes) : base(tok, name, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); + IsStatic = isStatic; } /// /// Returns className+"."+memberName. Available only after resolution. @@ -790,7 +792,7 @@ namespace Microsoft.Dafny { } public Field(IToken tok, string name, bool isGhost, bool isMutable, Type type, Attributes attributes) - : base(tok, name, attributes) { + : base(tok, name, false, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); @@ -825,13 +827,10 @@ namespace Microsoft.Dafny { public CouplingInvariant(List/*!*/ toks, Expression/*!*/ expr, Attributes attributes) - : base(toks[0], "_coupling_invariant" + getNames(toks), attributes) { + : base(toks[0], "_coupling_invariant" + getNames(toks), false, attributes) { Contract.Requires(toks.Count > 0); Expr = expr; Toks = toks; - - - } private static string getNames(List toks) { @@ -902,9 +901,6 @@ namespace Microsoft.Dafny { throw new NotImplementedException(); } } - - - } public abstract class NonglobalVariable : IVariable { @@ -1011,7 +1007,6 @@ namespace Microsoft.Dafny { } public class Function : MemberDecl, TypeParameter.ParentType { - public readonly bool IsStatic; public readonly bool IsGhost; // functions are "ghost" by default; a non-ghost function is called a "function method" public readonly bool IsUnlimited; public bool IsRecursive; // filled in during resolution @@ -1038,7 +1033,7 @@ namespace Microsoft.Dafny { public Function(IToken tok, string name, bool isStatic, bool isGhost, bool isUnlimited, [Captured] List/*!*/ typeArgs, [Captured] List/*!*/ formals, Type/*!*/ resultType, List/*!*/ req, List/*!*/ reads, List/*!*/ ens, List/*!*/ decreases, Expression body, Attributes attributes) - : base(tok, name, attributes) { + : base(tok, name, isStatic, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); @@ -1049,7 +1044,6 @@ namespace Microsoft.Dafny { Contract.Requires(cce.NonNullElements(reads)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases)); - this.IsStatic = isStatic; this.IsGhost = isGhost; this.IsUnlimited = isUnlimited; this.TypeArgs = typeArgs; @@ -1065,7 +1059,6 @@ namespace Microsoft.Dafny { } public class Method : MemberDecl, TypeParameter.ParentType { - public readonly bool IsStatic; public readonly bool IsGhost; public readonly List/*!*/ TypeArgs; public readonly List/*!*/ Ins; @@ -1096,7 +1089,7 @@ namespace Microsoft.Dafny { [Captured] List/*!*/ decreases, [Captured] BlockStmt body, Attributes attributes) - : base(tok, name, attributes) { + : base(tok, name, isStatic, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); @@ -1106,7 +1099,6 @@ namespace Microsoft.Dafny { Contract.Requires(cce.NonNullElements(mod)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases)); - this.IsStatic = isStatic; this.IsGhost = isGhost; this.TypeArgs = typeArgs; this.Ins = ins; @@ -1306,7 +1298,9 @@ namespace Microsoft.Dafny { } public abstract class DeterminedAssignmentRhs : AssignmentRhs { - internal DeterminedAssignmentRhs() { + public readonly IToken Tok; + internal DeterminedAssignmentRhs(IToken tok) { + Tok = tok; } } @@ -1317,7 +1311,9 @@ namespace Microsoft.Dafny { Contract.Invariant(Expr != null); } - public ExprRhs(Expression expr) { + public ExprRhs(Expression expr) + : base(expr.tok) + { Contract.Requires(expr != null); Expr = expr; } @@ -1336,16 +1332,22 @@ namespace Microsoft.Dafny { Contract.Invariant(ArrayDimensions == null || InitCall == null); } - public TypeRhs(Type type) { + public TypeRhs(IToken tok, Type type) + : base(tok) + { Contract.Requires(type != null); EType = type; } - public TypeRhs(Type type, CallStmt initCall) { + public TypeRhs(IToken tok, Type type, CallStmt initCall) + : base(tok) + { Contract.Requires(type != null); EType = type; InitCall = initCall; } - public TypeRhs(Type type, List arrayDimensions) { + public TypeRhs(IToken tok, Type type, List arrayDimensions) + : base(tok) + { Contract.Requires(type != null); Contract.Requires(arrayDimensions != null && 1 <= arrayDimensions.Count); EType = type; @@ -1365,7 +1367,7 @@ namespace Microsoft.Dafny { } } - public class CallRhs : AssignmentRhs + public class CallRhs : DeterminedAssignmentRhs { [ContractInvariantMethod] void ObjectInvariant() { @@ -1374,20 +1376,19 @@ namespace Microsoft.Dafny { Contract.Invariant(cce.NonNullElements(Args)); } - public readonly IToken Tok; public readonly Expression/*!*/ Receiver; public readonly string/*!*/ MethodName; public readonly List/*!*/ Args; public Method Method; // filled in by resolution public CallRhs(IToken tok, Expression/*!*/ receiver, string/*!*/ methodName, List/*!*/ args) + : base(tok) { Contract.Requires(tok != null); Contract.Requires(receiver != null); Contract.Requires(methodName != null); Contract.Requires(cce.NonNullElements(args)); - this.Tok = tok; this.Receiver = receiver; this.MethodName = methodName; this.Args = args; @@ -1408,6 +1409,35 @@ namespace Microsoft.Dafny { public override bool CanAffectPreviouslyKnownExpressions { get { return false; } } } + public abstract class ConcreteSyntaxStatement : Statement + { + public List ResolvedStatements = new List(); // contents filled in during resolution + public ConcreteSyntaxStatement(IToken tok) + : base(tok) { + } + } + + public class UpdateStmt : ConcreteSyntaxStatement + { + public readonly List Lhss; + public readonly List Rhss; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(Lhss)); + Contract.Invariant(cce.NonNullElements(Rhss)); + } + public UpdateStmt(IToken tok, List lhss, List rhss) + : base(tok) + { + Contract.Requires(tok != null); + Contract.Requires(cce.NonNullElements(lhss)); + Contract.Requires(cce.NonNullElements(rhss)); + Contract.Requires(lhss.Count != 0 || rhss.Count == 1); + Lhss = lhss; + Rhss = rhss; + } + } + public class AssignStmt : Statement { public readonly Expression/*!*/ Lhs; public readonly AssignmentRhs/*!*/ Rhs; @@ -1417,6 +1447,15 @@ namespace Microsoft.Dafny { Contract.Invariant(Rhs != null); } + public AssignStmt(IToken tok, Expression lhs, DeterminedAssignmentRhs rhs) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(lhs != null); + Contract.Requires(rhs != null); + this.Lhs = lhs; + this.Rhs = rhs; + } +#if OLD_STUFF public AssignStmt(IToken tok, Expression lhs, Expression rhs) : base(tok) { // ordinary assignment statement Contract.Requires(tok != null); @@ -1442,6 +1481,7 @@ namespace Microsoft.Dafny { this.Lhs = lhs; this.Rhs = new TypeRhs(type, arrayDimensions); } +#endif public AssignStmt(IToken tok, Expression lhs) : base(tok) { // havoc Contract.Requires(tok != null); @@ -1837,7 +1877,6 @@ namespace Microsoft.Dafny { var rr = r as ConcreteSyntaxExpression; if (rr == null) { break; } r = rr.ResolvedExpression; - Contract.Assert(r != null); // this is true if the expression is indeed resolved } return r; } @@ -1884,6 +1923,9 @@ namespace Microsoft.Dafny { this.tok = tok; } + /// + /// Returns the non-null subexpressions of the Expression. + /// public virtual IEnumerable SubExpressions { get { yield break; } } @@ -2113,7 +2155,7 @@ namespace Microsoft.Dafny { [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Array != null); - Contract.Invariant(Indices != null && cce.NonNullElements(Indices)); + Contract.Invariant(cce.NonNullElements(Indices)); Contract.Invariant(1 <= Indices.Count); } @@ -2121,7 +2163,7 @@ namespace Microsoft.Dafny { : base(tok) { Contract.Requires(tok != null); Contract.Requires(array != null); - Contract.Requires(indices == null && cce.NonNullElements(indices) && 1 <= indices.Count); + Contract.Requires(cce.NonNullElements(indices) && 1 <= indices.Count); Array = array; Indices = indices; @@ -2480,6 +2522,8 @@ namespace Microsoft.Dafny { public List Bounds; // initialized and filled in by resolver // invariant Bounds == null || Bounds.Count == BoundVars.Count; + public List MissingBounds; // filled in during resolution; remains "null" if bounds can be found + // invariant Bounds == null || MissingBounds == null; public ComprehensionExpr(IToken/*!*/ tok, List/*!*/ bvars, Expression range, Expression/*!*/ term, Attributes attrs) : base(tok) { @@ -2793,7 +2837,11 @@ namespace Microsoft.Dafny { : base(tok) { } public override IEnumerable SubExpressions { - get { yield return ResolvedExpression; } + get { + if (ResolvedExpression != null) { + yield return ResolvedExpression; + } + } } } diff --git a/Dafny/Parser.cs b/Dafny/Parser.cs index c2af1f2f..d0b5a146 100644 --- a/Dafny/Parser.cs +++ b/Dafny/Parser.cs @@ -20,7 +20,7 @@ public class Parser { public const int _digits = 2; public const int _arrayToken = 3; public const int _string = 4; - public const int maxT = 106; + public const int maxT = 107; const bool T = true; const bool x = false; @@ -379,7 +379,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List/*!*/ typeArgs) { @@ -498,7 +498,7 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, List/*!*/ decreases) { Expression(out e); Expect(15); ens.Add(new MaybeFreeExpression(e, isFree)); - } else SynErr(113); + } else SynErr(114); } else if (la.kind == 31) { Get(); Expressions(decreases); Expect(15); - } else SynErr(114); + } else SynErr(115); } void BlockStmt(out Statement/*!*/ block, out IToken bodyStart, out IToken bodyEnd) { @@ -882,7 +882,7 @@ List/*!*/ decreases) { GenericInstantiation(gt); } ty = new UserDefinedType(tok, tok.val, gt); - } else SynErr(115); + } else SynErr(116); } void FunctionSpec(List/*!*/ reqs, List/*!*/ reads, List/*!*/ ens, List/*!*/ decreases) { @@ -914,7 +914,7 @@ List/*!*/ decreases) { Get(); Expressions(decreases); Expect(15); - } else SynErr(116); + } else SynErr(117); } void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) { @@ -925,7 +925,7 @@ List/*!*/ decreases) { MatchExpression(out e); } else if (StartOf(8)) { Expression(out e); - } else SynErr(117); + } else SynErr(118); Expect(8); bodyEnd = t; } @@ -937,7 +937,7 @@ List/*!*/ decreases) { fe = new FrameExpression(new WildcardExpr(t), null); } else if (StartOf(8)) { FrameExpression(out fe); - } else SynErr(118); + } else SynErr(119); } void PossiblyWildExpression(out Expression/*!*/ e) { @@ -948,7 +948,7 @@ List/*!*/ decreases) { e = new WildcardExpr(t); } else if (StartOf(8)) { Expression(out e); - } else SynErr(119); + } else SynErr(120); } void MatchExpression(out Expression/*!*/ e) { @@ -1002,83 +1002,58 @@ List/*!*/ decreases) { MatchExpression(out e); } else if (StartOf(8)) { Expression(out e); - } else SynErr(120); + } else SynErr(121); } void Stmt(List/*!*/ ss) { Contract.Requires(cce.NonNullElements(ss)); Statement/*!*/ s; IToken bodyStart, bodyEnd; - while (la.kind == 7) { - BlockStmt(out s, out bodyStart, out bodyEnd); - ss.Add(s); - } if (StartOf(11)) { OneStmt(out s); ss.Add(s); } else if (la.kind == 11 || la.kind == 18) { VarDeclStmts(ss); - } else SynErr(121); + } else SynErr(122); } void OneStmt(out Statement/*!*/ s) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; IToken/*!*/ id; string label = null; s = dummyStmt; /* to please the compiler */ + IToken bodyStart, bodyEnd; - switch (la.kind) { - case 64: { + if (la.kind == 7) { + BlockStmt(out s, out bodyStart, out bodyEnd); + } else if (la.kind == 65) { AssertStmt(out s); - break; - } - case 65: { + } else if (la.kind == 66) { AssumeStmt(out s); - break; - } - case 66: { + } else if (la.kind == 67) { UseStmt(out s); - break; - } - case 67: { + } else if (la.kind == 68) { PrintStmt(out s); - break; - } - case 1: case 32: case 94: case 97: { - AssignStmt(out s, true); - break; - } - case 56: { + } else if (la.kind == 57) { HavocStmt(out s); - break; - } - case 61: { + } else if (la.kind == 62) { CallStmt(out s); - break; - } - case 57: { + } else if (la.kind == 47) { + Get(); + UpdateStmt(out s); + } else if (la.kind == 58) { IfStmt(out s); - break; - } - case 59: { + } else if (la.kind == 60) { WhileStmt(out s); - break; - } - case 44: { + } else if (la.kind == 44) { MatchStmt(out s); - break; - } - case 62: { + } else if (la.kind == 63) { ForeachStmt(out s); - break; - } - case 47: { + } else if (la.kind == 48) { Get(); x = t; Ident(out id); Expect(22); s = new LabelStmt(x, id.val); - break; - } - case 48: { + } else if (la.kind == 49) { Get(); x = t; if (la.kind == 1) { @@ -1087,17 +1062,14 @@ List/*!*/ decreases) { } Expect(15); s = new BreakStmt(x, label); - break; - } - case 49: { + } else if (la.kind == 50) { Get(); x = t; Expect(15); s = new ReturnStmt(x); - break; - } - default: SynErr(122); break; - } + } else if (StartOf(12)) { + UpdateStmt(out s); + } else SynErr(123); } void VarDeclStmts(List/*!*/ ss) { @@ -1119,7 +1091,7 @@ List/*!*/ decreases) { void AssertStmt(out Statement/*!*/ s) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; - Expect(64); + Expect(65); x = t; Expression(out e); Expect(15); @@ -1128,7 +1100,7 @@ List/*!*/ decreases) { void AssumeStmt(out Statement/*!*/ s) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; - Expect(65); + Expect(66); x = t; Expression(out e); Expect(15); @@ -1137,7 +1109,7 @@ List/*!*/ decreases) { void UseStmt(out Statement/*!*/ s) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ e; - Expect(66); + Expect(67); x = t; Expression(out e); Expect(15); @@ -1148,7 +1120,7 @@ List/*!*/ decreases) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Attributes.Argument/*!*/ arg; List args = new List(); - Expect(67); + Expect(68); x = t; AttributeArg(out arg); args.Add(arg); @@ -1161,40 +1133,9 @@ List/*!*/ decreases) { s = new PrintStmt(x, args); } - void AssignStmt(out Statement/*!*/ s, bool allowChoose) { - Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; - Expression/*!*/ lhs; - List rhs; - Type ty; - s = dummyStmt; - CallStmt initCall = null; - - LhsExpr(out lhs); - Expect(50); - x = t; - AssignRhs(out rhs, out ty, out initCall, lhs); - if (ty == null) { - Contract.Assert(rhs != null); - Contract.Assert(rhs.Count == 1); - s = new AssignStmt(x, lhs, rhs[0]); - if (!allowChoose) { - var r = rhs[0] as UnaryExpr; - if (r != null && r.Op == UnaryExpr.Opcode.SetChoose) { - SemErr("choose operator not allowed as RHS in foreach assignment"); - } - } - } else if (rhs == null) { - s = new AssignStmt(x, lhs, ty, initCall); - } else { - s = new AssignStmt(x, lhs, ty, rhs); - } - - Expect(15); - } - void HavocStmt(out Statement/*!*/ s) { Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Expression/*!*/ lhs; - Expect(56); + Expect(57); x = t; LhsExpr(out lhs); Expect(15); @@ -1207,10 +1148,10 @@ List/*!*/ decreases) { List lhs = new List(); List newVars = new List(); - Expect(61); + Expect(62); x = t; CallStmtSubExpr(out e); - if (la.kind == 19 || la.kind == 50) { + if (la.kind == 19 || la.kind == 51) { if (la.kind == 19) { Get(); e = ConvertToLocal(e); @@ -1229,7 +1170,7 @@ List/*!*/ decreases) { Ident(out id); RecordCallLhs(new IdentifierExpr(id, id.val), lhs, newVars); } - Expect(50); + Expect(51); CallStmtSubExpr(out e); } else { Get(); @@ -1256,6 +1197,39 @@ List/*!*/ decreases) { } + void UpdateStmt(out Statement/*!*/ s) { + List lhss = new List(); + List rhss = new List(); + Expression e; DeterminedAssignmentRhs r; + Expression lhs0; + IToken x; + + Lhs(out e); + x = e.tok; + if (la.kind == 15) { + Get(); + rhss.Add(new ExprRhs(e)); + } else if (la.kind == 19 || la.kind == 51) { + lhss.Add(e); lhs0 = e; + while (la.kind == 19) { + Get(); + Lhs(out e); + lhss.Add(e); + } + Expect(51); + x = t; + Rhs(out r, lhs0); + rhss.Add(r); + while (la.kind == 19) { + Get(); + Rhs(out r, lhs0); + rhss.Add(r); + } + Expect(15); + } else SynErr(124); + s = new UpdateStmt(x, lhss, rhss); + } + void IfStmt(out Statement/*!*/ ifStmt) { Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x; Expression guard; @@ -1266,26 +1240,26 @@ List/*!*/ decreases) { List alternatives; ifStmt = dummyStmt; // to please the compiler - Expect(57); + Expect(58); x = t; if (la.kind == 32) { Guard(out guard); BlockStmt(out thn, out bodyStart, out bodyEnd); - if (la.kind == 58) { + if (la.kind == 59) { Get(); - if (la.kind == 57) { + if (la.kind == 58) { IfStmt(out s); els = s; } else if (la.kind == 7) { BlockStmt(out s, out bodyStart, out bodyEnd); els = s; - } else SynErr(123); + } else SynErr(125); } ifStmt = new IfStmt(x, guard, thn, els); } else if (la.kind == 7) { AlternativeBlock(out alternatives); ifStmt = new AlternativeStmt(x, alternatives); - } else SynErr(124); + } else SynErr(126); } void WhileStmt(out Statement/*!*/ stmt) { @@ -1298,7 +1272,7 @@ List/*!*/ decreases) { List alternatives; stmt = dummyStmt; // to please the compiler - Expect(59); + Expect(60); x = t; if (la.kind == 32) { Guard(out guard); @@ -1306,11 +1280,11 @@ List/*!*/ decreases) { LoopSpec(out invariants, out decreases); BlockStmt(out body, out bodyStart, out bodyEnd); stmt = new WhileStmt(x, guard, invariants, decreases, body); - } else if (StartOf(12)) { + } else if (StartOf(13)) { LoopSpec(out invariants, out decreases); AlternativeBlock(out alternatives); stmt = new AlternativeLoopStmt(x, invariants, decreases, alternatives); - } else SynErr(125); + } else SynErr(127); } void MatchStmt(out Statement/*!*/ s) { @@ -1338,7 +1312,7 @@ List/*!*/ decreases) { AssignStmt bodyAssign = null; parseVarScope.PushMarker(); - Expect(62); + Expect(63); x = t; range = new LiteralExpr(x, true); ty = new InferredTypeProxy(); @@ -1349,7 +1323,7 @@ List/*!*/ decreases) { Get(); Type(out ty); } - Expect(63); + Expect(64); Expression(out collection); parseVarScope.Push(boundVar.val, boundVar.val); if (la.kind == 17) { @@ -1358,11 +1332,11 @@ List/*!*/ decreases) { } Expect(33); Expect(7); - while (la.kind == 64 || la.kind == 65 || la.kind == 66) { - if (la.kind == 64) { + while (la.kind == 65 || la.kind == 66 || la.kind == 67) { + if (la.kind == 65) { AssertStmt(out s); if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } - } else if (la.kind == 65) { + } else if (la.kind == 66) { AssumeStmt(out s); if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } } else { @@ -1370,13 +1344,13 @@ List/*!*/ decreases) { if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } } } - if (StartOf(13)) { + if (StartOf(14)) { AssignStmt(out s, false); if (s is AssignStmt) { bodyAssign = (AssignStmt)s; } - } else if (la.kind == 56) { + } else if (la.kind == 57) { HavocStmt(out s); if (s is AssignStmt) { bodyAssign = (AssignStmt)s; } - } else SynErr(126); + } else SynErr(128); Expect(8); if (bodyAssign != null) { s = new ForeachStmt(x, new BoundVar(boundVar, boundVar.val, ty), collection, range, bodyPrefix, bodyAssign); @@ -1387,26 +1361,127 @@ List/*!*/ decreases) { parseVarScope.PopMarker(); } + void Lhs(out Expression e) { + e = null; // to please the compiler + + if (la.kind == 1) { + DottedIdentifiersAndFunction(out e); + while (la.kind == 53 || la.kind == 55) { + Suffix(ref e); + } + } else if (StartOf(15)) { + ConstAtomExpression(out e); + Suffix(ref e); + while (la.kind == 53 || la.kind == 55) { + Suffix(ref e); + } + } else SynErr(129); + } + + void Rhs(out DeterminedAssignmentRhs r, Expression receiverForInitCall) { + IToken/*!*/ x, newToken; Expression/*!*/ e; + List ee = null; + Type ty = null; + CallStmt initCall = null; + List args; + r = null; // to please compiler + + if (la.kind == 52) { + Get(); + newToken = t; + TypeAndToken(out x, out ty); + if (la.kind == 53 || la.kind == 55) { + if (la.kind == 53) { + Get(); + ee = new List(); + Expressions(ee); + Expect(54); + UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true); + + } else { + Get(); + Ident(out x); + Expect(32); + args = new List(); + if (StartOf(8)) { + Expressions(args); + } + Expect(33); + initCall = new CallStmt(x, new List(), new List(), + receiverForInitCall, x.val, args); + } + } + if (ee != null) { + r = new TypeRhs(newToken, ty, ee); + } else { + r = new TypeRhs(newToken, ty, initCall); + } + + } else if (la.kind == 56) { + Get(); + x = t; + Expression(out e); + r = new ExprRhs(new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e)); + } else if (StartOf(8)) { + Expression(out e); + r = new ExprRhs(e); + } else SynErr(130); + } + + void AssignStmt(out Statement/*!*/ s, bool allowChoose) { + Contract.Ensures(Contract.ValueAtReturn(out s) != null); + IToken/*!*/ x, rhsTok; + Expression/*!*/ lhs; + List rhs; + Type ty; + s = dummyStmt; + CallStmt initCall = null; + + LhsExpr(out lhs); + Expect(51); + x = t; + AssignRhs(out rhsTok, out rhs, out ty, out initCall, lhs); + if (ty == null) { + Contract.Assert(rhs != null); + Contract.Assert(rhs.Count == 1); + s = new AssignStmt(x, lhs, new ExprRhs(rhs[0])); + if (!allowChoose) { + var r = rhs[0] as UnaryExpr; + if (r != null && r.Op == UnaryExpr.Opcode.SetChoose) { + SemErr("choose operator not allowed as RHS in foreach assignment"); + } + } + } else if (rhs == null) { + s = new AssignStmt(x, lhs, new TypeRhs(rhsTok, ty, initCall)); + } else { + s = new AssignStmt(x, lhs, new TypeRhs(rhsTok, ty, rhs)); + } + + Expect(15); + } + void LhsExpr(out Expression/*!*/ e) { Contract.Ensures(Contract.ValueAtReturn(out e)!=null); SelectExpression(out e); } - void AssignRhs(out List ee, out Type ty, out CallStmt initCall, Expression receiverForInitCall) { + void AssignRhs(out IToken tok, out List ee, out Type ty, out CallStmt initCall, Expression receiverForInitCall) { IToken/*!*/ x; Expression/*!*/ e; ee = null; ty = null; initCall = null; List args; + tok = Token.NoToken; // to please compiler - if (la.kind == 51) { + if (la.kind == 52) { Get(); + tok = t; TypeAndToken(out x, out ty); - if (la.kind == 52 || la.kind == 54) { - if (la.kind == 52) { + if (la.kind == 53 || la.kind == 55) { + if (la.kind == 53) { Get(); ee = new List(); Expressions(ee); - Expect(53); + Expect(54); UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true); } else { @@ -1422,17 +1497,17 @@ List/*!*/ decreases) { receiverForInitCall, x.val, args); } } - } else if (la.kind == 55) { + } else if (la.kind == 56) { Get(); - x = t; + x = t; tok = t; Expression(out e); e = new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e); ee = new List() { e }; } else if (StartOf(8)) { Expression(out e); - ee = new List() { e }; - } else SynErr(127); + tok = e.tok; ee = new List() { e }; + } else SynErr(131); if (ee == null && ty == null) { ee = new List() { dummyExpr}; } } @@ -1440,16 +1515,17 @@ List/*!*/ decreases) { Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr; if (la.kind == 1) { IdentOrFuncExpression(out e); - } else if (la.kind == 32 || la.kind == 94 || la.kind == 97) { + } else if (la.kind == 32 || la.kind == 95 || la.kind == 98) { ObjectExpression(out e); - } else SynErr(128); - while (la.kind == 52 || la.kind == 54) { + } else SynErr(132); + while (la.kind == 53 || la.kind == 55) { SelectOrCallSuffix(ref e); } } void IdentTypeRhs(out VarDecl/*!*/ d, bool isGhost) { - Contract.Ensures(Contract.ValueAtReturn(out d) != null); IToken/*!*/ id; Type/*!*/ ty; + Contract.Ensures(Contract.ValueAtReturn(out d) != null); + IToken/*!*/ id, rhsTok = null; Type/*!*/ ty; List rhs = null; Type newType = null; Type optionalType = null; DeterminedAssignmentRhs optionalRhs = null; CallStmt initCall = null; @@ -1460,18 +1536,18 @@ List/*!*/ decreases) { Type(out ty); optionalType = ty; } - if (la.kind == 50) { + if (la.kind == 51) { Get(); - AssignRhs(out rhs, out newType, out initCall, new IdentifierExpr(id, id.val)); + AssignRhs(out rhsTok, out rhs, out newType, out initCall, new IdentifierExpr(id, id.val)); } if (newType == null && rhs != null) { Contract.Assert(rhs.Count == 1); optionalRhs = new ExprRhs(rhs[0]); } else if (newType != null) { if (rhs == null) { - optionalRhs = new TypeRhs(newType, initCall); + optionalRhs = new TypeRhs(rhsTok, newType, initCall); } else { - optionalRhs = new TypeRhs(newType, rhs); + optionalRhs = new TypeRhs(rhsTok, newType, rhs); } } else if (optionalType == null) { optionalType = new InferredTypeProxy(); @@ -1489,7 +1565,7 @@ List/*!*/ decreases) { } else if (StartOf(8)) { Expression(out ee); e = ee; - } else SynErr(129); + } else SynErr(133); Expect(33); } @@ -1521,14 +1597,14 @@ List/*!*/ decreases) { invariants = new List(); decreases = new List(); - while (la.kind == 28 || la.kind == 31 || la.kind == 60) { - if (la.kind == 28 || la.kind == 60) { + while (la.kind == 28 || la.kind == 31 || la.kind == 61) { + if (la.kind == 28 || la.kind == 61) { isFree = false; if (la.kind == 28) { Get(); isFree = true; } - Expect(60); + Expect(61); Expression(out e); invariants.Add(new MaybeFreeExpression(e, isFree)); Expect(15); @@ -1582,11 +1658,11 @@ List/*!*/ decreases) { Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr; if (la.kind == 1) { IdentOrFuncExpression(out e); - } else if (la.kind == 32 || la.kind == 94 || la.kind == 97) { + } else if (la.kind == 32 || la.kind == 95 || la.kind == 98) { ObjectExpression(out e); SelectOrCallSuffix(ref e); - } else SynErr(130); - while (la.kind == 52 || la.kind == 54) { + } else SynErr(134); + while (la.kind == 53 || la.kind == 55) { SelectOrCallSuffix(ref e); } } @@ -1599,13 +1675,13 @@ List/*!*/ decreases) { } else if (StartOf(8)) { Expression(out e); arg = new Attributes.Argument(e); - } else SynErr(131); + } else SynErr(135); } void EquivExpression(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; ImpliesExpression(out e0); - while (la.kind == 68 || la.kind == 69) { + while (la.kind == 69 || la.kind == 70) { EquivOp(); x = t; ImpliesExpression(out e1); @@ -1616,7 +1692,7 @@ List/*!*/ decreases) { void ImpliesExpression(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; LogicalExpression(out e0); - if (la.kind == 70 || la.kind == 71) { + if (la.kind == 71 || la.kind == 72) { ImpliesOp(); x = t; ImpliesExpression(out e1); @@ -1625,23 +1701,23 @@ List/*!*/ decreases) { } void EquivOp() { - if (la.kind == 68) { + if (la.kind == 69) { Get(); - } else if (la.kind == 69) { + } else if (la.kind == 70) { Get(); - } else SynErr(132); + } else SynErr(136); } void LogicalExpression(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; RelationalExpression(out e0); - if (StartOf(14)) { - if (la.kind == 72 || la.kind == 73) { + if (StartOf(16)) { + if (la.kind == 73 || la.kind == 74) { AndOp(); x = t; RelationalExpression(out e1); e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); - while (la.kind == 72 || la.kind == 73) { + while (la.kind == 73 || la.kind == 74) { AndOp(); x = t; RelationalExpression(out e1); @@ -1652,7 +1728,7 @@ List/*!*/ decreases) { x = t; RelationalExpression(out e1); e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); - while (la.kind == 74 || la.kind == 75) { + while (la.kind == 75 || la.kind == 76) { OrOp(); x = t; RelationalExpression(out e1); @@ -1663,17 +1739,17 @@ List/*!*/ decreases) { } void ImpliesOp() { - if (la.kind == 70) { + if (la.kind == 71) { Get(); - } else if (la.kind == 71) { + } else if (la.kind == 72) { Get(); - } else SynErr(133); + } else SynErr(137); } void RelationalExpression(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op; Term(out e0); - if (StartOf(15)) { + if (StartOf(17)) { RelOp(out x, out op); Term(out e1); e0 = new BinaryExpr(x, op, e0, e1); @@ -1681,25 +1757,25 @@ List/*!*/ decreases) { } void AndOp() { - if (la.kind == 72) { + if (la.kind == 73) { Get(); - } else if (la.kind == 73) { + } else if (la.kind == 74) { Get(); - } else SynErr(134); + } else SynErr(138); } void OrOp() { - if (la.kind == 74) { + if (la.kind == 75) { Get(); - } else if (la.kind == 75) { + } else if (la.kind == 76) { Get(); - } else SynErr(135); + } else SynErr(139); } void Term(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op; Factor(out e0); - while (la.kind == 85 || la.kind == 86) { + while (la.kind == 86 || la.kind == 87) { AddOp(out x, out op); Factor(out e1); e0 = new BinaryExpr(x, op, e0, e1); @@ -1709,7 +1785,7 @@ List/*!*/ decreases) { void RelOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) { Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/; switch (la.kind) { - case 76: { + case 77: { Get(); x = t; op = BinaryExpr.Opcode.Eq; break; @@ -1724,59 +1800,59 @@ List/*!*/ decreases) { x = t; op = BinaryExpr.Opcode.Gt; break; } - case 77: { + case 78: { Get(); x = t; op = BinaryExpr.Opcode.Le; break; } - case 78: { + case 79: { Get(); x = t; op = BinaryExpr.Opcode.Ge; break; } - case 79: { + case 80: { Get(); x = t; op = BinaryExpr.Opcode.Neq; break; } - case 80: { + case 81: { Get(); x = t; op = BinaryExpr.Opcode.Disjoint; break; } - case 63: { + case 64: { Get(); x = t; op = BinaryExpr.Opcode.In; break; } - case 81: { + case 82: { Get(); x = t; op = BinaryExpr.Opcode.NotIn; break; } - case 82: { + case 83: { Get(); x = t; op = BinaryExpr.Opcode.Neq; break; } - case 83: { + case 84: { Get(); x = t; op = BinaryExpr.Opcode.Le; break; } - case 84: { + case 85: { Get(); x = t; op = BinaryExpr.Opcode.Ge; break; } - default: SynErr(136); break; + default: SynErr(140); break; } } void Factor(out Expression/*!*/ e0) { Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op; UnaryExpression(out e0); - while (la.kind == 42 || la.kind == 87 || la.kind == 88) { + while (la.kind == 42 || la.kind == 88 || la.kind == 89) { MulOp(out x, out op); UnaryExpression(out e1); e0 = new BinaryExpr(x, op, e0, e1); @@ -1785,40 +1861,40 @@ List/*!*/ decreases) { 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 == 85) { + if (la.kind == 86) { Get(); x = t; op = BinaryExpr.Opcode.Add; - } else if (la.kind == 86) { + } else if (la.kind == 87) { Get(); x = t; op = BinaryExpr.Opcode.Sub; - } else SynErr(137); + } else SynErr(141); } void UnaryExpression(out Expression/*!*/ e) { Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr; - if (la.kind == 86) { + if (la.kind == 87) { Get(); x = t; UnaryExpression(out e); e = new BinaryExpr(x, BinaryExpr.Opcode.Sub, new LiteralExpr(x, 0), e); - } else if (la.kind == 89 || la.kind == 90) { + } else if (la.kind == 90 || la.kind == 91) { NegOp(); x = t; UnaryExpression(out e); e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e); - } else if (StartOf(16)) { + } else if (StartOf(18)) { EndlessExpression(out e); } else if (la.kind == 1) { DottedIdentifiersAndFunction(out e); - while (la.kind == 52 || la.kind == 54) { + while (la.kind == 53 || la.kind == 55) { Suffix(ref e); } - } else if (StartOf(17)) { + } else if (StartOf(15)) { ConstAtomExpression(out e); - while (la.kind == 52 || la.kind == 54) { + while (la.kind == 53 || la.kind == 55) { Suffix(ref e); } - } else SynErr(138); + } else SynErr(142); } void MulOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) { @@ -1826,21 +1902,21 @@ List/*!*/ decreases) { if (la.kind == 42) { Get(); x = t; op = BinaryExpr.Opcode.Mul; - } else if (la.kind == 87) { + } else if (la.kind == 88) { Get(); x = t; op = BinaryExpr.Opcode.Div; - } else if (la.kind == 88) { + } else if (la.kind == 89) { Get(); x = t; op = BinaryExpr.Opcode.Mod; - } else SynErr(139); + } else SynErr(143); } void NegOp() { - if (la.kind == 89) { + if (la.kind == 90) { Get(); - } else if (la.kind == 90) { + } else if (la.kind == 91) { Get(); - } else SynErr(140); + } else SynErr(144); } void EndlessExpression(out Expression e) { @@ -1849,20 +1925,20 @@ List/*!*/ decreases) { Expression e0, e1; e = dummyExpr; - if (la.kind == 57) { + if (la.kind == 58) { Get(); x = t; Expression(out e); - Expect(98); + Expect(99); Expression(out e0); - Expect(58); + Expect(59); Expression(out e1); e = new ITEExpr(x, e, e0, e1); - } else if (StartOf(18)) { + } else if (StartOf(19)) { QuantifierGuts(out e); } else if (la.kind == 37) { ComprehensionExpr(out e); - } else SynErr(141); + } else SynErr(145); } void DottedIdentifiersAndFunction(out Expression e) { @@ -1872,7 +1948,7 @@ List/*!*/ decreases) { Ident(out id); idents.Add(id); - while (la.kind == 54) { + while (la.kind == 55) { Get(); Ident(out id); idents.Add(id); @@ -1899,17 +1975,17 @@ List/*!*/ decreases) { e = dummyExpr; switch (la.kind) { - case 91: { + case 92: { Get(); e = new LiteralExpr(t, false); break; } - case 92: { + case 93: { Get(); e = new LiteralExpr(t, true); break; } - case 93: { + case 94: { Get(); e = new LiteralExpr(t); break; @@ -1919,12 +1995,12 @@ List/*!*/ decreases) { e = new LiteralExpr(t, n); break; } - case 94: { + case 95: { Get(); e = new ThisExpr(t); break; } - case 95: { + case 96: { Get(); x = t; Expect(32); @@ -1933,7 +2009,7 @@ List/*!*/ decreases) { e = new FreshExpr(x, e); break; } - case 96: { + case 97: { Get(); x = t; Expect(32); @@ -1942,7 +2018,7 @@ List/*!*/ decreases) { e = new AllocatedExpr(x, e); break; } - case 97: { + case 98: { Get(); x = t; Expect(32); @@ -1969,14 +2045,14 @@ List/*!*/ decreases) { Expect(8); break; } - case 52: { + case 53: { Get(); x = t; elements = new List(); if (StartOf(8)) { Expressions(elements); } e = new SeqDisplayExpr(x, elements); - Expect(53); + Expect(54); break; } case 32: { @@ -1987,7 +2063,7 @@ List/*!*/ decreases) { Expect(33); break; } - default: SynErr(142); break; + default: SynErr(146); break; } } @@ -2012,13 +2088,13 @@ List/*!*/ decreases) { Expression range = null; Expression/*!*/ body; - if (la.kind == 100 || la.kind == 101) { + if (la.kind == 101 || la.kind == 102) { Forall(); x = t; univ = true; - } else if (la.kind == 102 || la.kind == 103) { + } else if (la.kind == 103 || la.kind == 104) { Exists(); x = t; - } else SynErr(143); + } else SynErr(147); parseVarScope.PushMarker(); IdentTypeOptional(out bv); bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); @@ -2065,7 +2141,7 @@ List/*!*/ decreases) { } Expect(17); Expression(out range); - if (la.kind == 104 || la.kind == 105) { + if (la.kind == 105 || la.kind == 106) { QSep(); Expression(out body); } @@ -2099,10 +2175,10 @@ List/*!*/ decreases) { void ObjectExpression(out Expression/*!*/ e) { Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr; - if (la.kind == 94) { + if (la.kind == 95) { Get(); e = new ThisExpr(t); - } else if (la.kind == 97) { + } else if (la.kind == 98) { Get(); x = t; Expect(32); @@ -2113,7 +2189,7 @@ List/*!*/ decreases) { Get(); Expression(out e); Expect(33); - } else SynErr(144); + } else SynErr(148); } void SelectOrCallSuffix(ref Expression/*!*/ e) { @@ -2122,7 +2198,7 @@ List/*!*/ decreases) { List multipleIndices = null; bool func = false; - if (la.kind == 54) { + if (la.kind == 55) { Get(); Ident(out id); if (la.kind == 32) { @@ -2135,24 +2211,24 @@ List/*!*/ decreases) { e = new FunctionCallExpr(id, id.val, e, args); } if (!func) { e = new FieldSelectExpr(id, e, id.val); } - } else if (la.kind == 52) { + } else if (la.kind == 53) { Get(); x = t; if (StartOf(8)) { Expression(out ee); e0 = ee; - if (la.kind == 99) { + if (la.kind == 100) { Get(); anyDots = true; if (StartOf(8)) { Expression(out ee); e1 = ee; } - } else if (la.kind == 50) { + } else if (la.kind == 51) { Get(); Expression(out ee); e1 = ee; - } else if (la.kind == 19 || la.kind == 53) { + } else if (la.kind == 19 || la.kind == 54) { while (la.kind == 19) { Get(); Expression(out ee); @@ -2163,12 +2239,12 @@ List/*!*/ decreases) { multipleIndices.Add(ee); } - } else SynErr(145); - } else if (la.kind == 99) { + } else SynErr(149); + } else if (la.kind == 100) { Get(); Expression(out ee); anyDots = true; e1 = ee; - } else SynErr(146); + } else SynErr(150); if (multipleIndices != null) { e = new MultiSelectExpr(x, e, multipleIndices); // make sure an array class with this dimensionality exists @@ -2191,24 +2267,24 @@ List/*!*/ decreases) { } } - Expect(53); - } else SynErr(147); + Expect(54); + } else SynErr(151); } void Forall() { - if (la.kind == 100) { + if (la.kind == 101) { Get(); - } else if (la.kind == 101) { + } else if (la.kind == 102) { Get(); - } else SynErr(148); + } else SynErr(152); } void Exists() { - if (la.kind == 102) { + if (la.kind == 103) { Get(); - } else if (la.kind == 103) { + } else if (la.kind == 104) { Get(); - } else SynErr(149); + } else SynErr(153); } void AttributeOrTrigger(ref Attributes attrs, ref Triggers trigs) { @@ -2221,16 +2297,16 @@ List/*!*/ decreases) { es = new List(); Expressions(es); trigs = new Triggers(es, trigs); - } else SynErr(150); + } else SynErr(154); Expect(8); } void QSep() { - if (la.kind == 104) { + if (la.kind == 105) { Get(); - } else if (la.kind == 105) { + } else if (la.kind == 106) { Get(); - } else SynErr(151); + } else SynErr(155); } void AttributeBody(ref Attributes attrs) { @@ -2241,7 +2317,7 @@ List/*!*/ decreases) { Expect(22); Expect(1); aName = t.val; - if (StartOf(19)) { + if (StartOf(20)) { AttributeArg(out aArg); aArgs.Add(aArg); while (la.kind == 19) { @@ -2265,26 +2341,27 @@ List/*!*/ decreases) { } static readonly bool[,]/*!*/ set = { - {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,x,x, x,T,T,T, T,T,T,x, x,x,T,x, T,x,x,x, x,T,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,T,T, T,T,x,x, x,x,T,x, T,x,x,x, x,T,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, x,x,x,x, x,T,T,T, 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,T, 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,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, 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,T, 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,T,x,T, 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,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,x, x,x,x,x, x,x,x,x, x,x,x,x}, - {x,T,T,x, x,x,x,T, 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,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,T,x,x, T,T,T,T, x,x,x,x}, - {x,T,x,x, x,x,x,T, x,x,x,T, 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,x,x, x,x,x,x, T,x,x,T, T,T,x,x, x,x,x,x, T,T,x,T, x,T,T,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,T,x, x,T,x,x, x,x,x,x, x,x,x,x}, - {x,T,T,x, x,x,x,T, 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,x,x, x,T,x,x, x,x,T,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,T,x,x, T,T,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, T,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,x,x, x,x,x,x, T,T,x,T, x,T,T,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,T,x, x,T,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, 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,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,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,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,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,T, x,x,x,x, x,x,x,x, x,x,x,x, 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, x,x,x,x, x,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,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,T,T,T, x,x,x,x}, - {x,x,T,x, x,x,x,T, 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,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,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,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, 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,T,T,x, T,x,x,T, 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,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,T,x,x, T,T,T,T, 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, 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,x, x,x,T,x, T,x,x,x, x,T,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,T,T, T,T,x,x, x,x,T,x, T,x,x,x, x,T,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,x, x,x,x,x, x,T,T,T, 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,T, 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,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,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,T, 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,T,x,T, 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,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,x, x,x,x,x, x,x,x,x, x,x,x,x, x}, + {x,T,T,x, x,x,x,T, 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,x,x, x,T,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,T,T, T,T,T,T, T,T,T,x, x,T,T,T, T,x,x,x, x}, + {x,T,T,x, x,x,x,T, x,x,x,T, x,x,x,x, x,T,T,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,T, T,T,T,x, x,T,x,x, x,T,T,x, T,x,T,T, 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, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x}, + {x,T,T,x, x,x,x,T, 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,x,x, x,T,x,x, x,x,T,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,T,T, T,T,T,T, T,T,T,x, x,T,T,T, T,x,x,x, x}, + {x,T,T,x, x,x,x,T, 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,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,x, x,T,x,x, x,T,T,x, T,x,T,T, 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, T,T,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x}, + {x,T,T,x, x,x,x,T, 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,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, T,T,T,T, T,T,T,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, 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,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,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,T, 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,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,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, 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,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,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,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,x,x,x, x,x,x,x, x,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, x,x,x,x, x,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,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,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,T,T,T, T,x,x,x, x}, + {x,T,T,x, T,x,x,T, 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,x,x, x,T,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, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,T,T, T,T,T,T, T,T,T,x, x,T,T,T, T,x,x,x, x} }; } // end Parser @@ -2356,111 +2433,115 @@ public class Errors { case 44: s = "\"match\" expected"; break; case 45: s = "\"case\" expected"; break; case 46: s = "\"=>\" expected"; break; - case 47: s = "\"label\" expected"; break; - case 48: s = "\"break\" expected"; break; - case 49: s = "\"return\" expected"; break; - case 50: s = "\":=\" expected"; break; - case 51: s = "\"new\" expected"; break; - case 52: s = "\"[\" expected"; break; - case 53: s = "\"]\" expected"; break; - case 54: s = "\".\" expected"; break; - case 55: s = "\"choose\" expected"; break; - case 56: s = "\"havoc\" expected"; break; - case 57: s = "\"if\" expected"; break; - case 58: s = "\"else\" expected"; break; - case 59: s = "\"while\" expected"; break; - case 60: s = "\"invariant\" expected"; break; - case 61: s = "\"call\" expected"; break; - case 62: s = "\"foreach\" expected"; break; - case 63: s = "\"in\" expected"; break; - case 64: s = "\"assert\" expected"; break; - case 65: s = "\"assume\" expected"; break; - case 66: s = "\"use\" expected"; break; - case 67: s = "\"print\" expected"; break; - case 68: s = "\"<==>\" expected"; break; - case 69: s = "\"\\u21d4\" expected"; break; - case 70: s = "\"==>\" expected"; break; - case 71: s = "\"\\u21d2\" expected"; break; - case 72: s = "\"&&\" expected"; break; - case 73: s = "\"\\u2227\" expected"; break; - case 74: s = "\"||\" expected"; break; - case 75: s = "\"\\u2228\" expected"; break; - case 76: s = "\"==\" expected"; break; - case 77: s = "\"<=\" expected"; break; - case 78: s = "\">=\" expected"; break; - case 79: s = "\"!=\" expected"; break; - case 80: s = "\"!!\" expected"; break; - case 81: s = "\"!in\" expected"; break; - case 82: s = "\"\\u2260\" expected"; break; - case 83: s = "\"\\u2264\" expected"; break; - case 84: s = "\"\\u2265\" expected"; break; - case 85: s = "\"+\" expected"; break; - case 86: s = "\"-\" expected"; break; - case 87: s = "\"/\" expected"; break; - case 88: s = "\"%\" expected"; break; - case 89: s = "\"!\" expected"; break; - case 90: s = "\"\\u00ac\" expected"; break; - case 91: s = "\"false\" expected"; break; - case 92: s = "\"true\" expected"; break; - case 93: s = "\"null\" expected"; break; - case 94: s = "\"this\" expected"; break; - case 95: s = "\"fresh\" expected"; break; - case 96: s = "\"allocated\" expected"; break; - case 97: s = "\"old\" expected"; break; - case 98: s = "\"then\" expected"; break; - case 99: s = "\"..\" expected"; break; - case 100: s = "\"forall\" expected"; break; - case 101: s = "\"\\u2200\" expected"; break; - case 102: s = "\"exists\" expected"; break; - case 103: s = "\"\\u2203\" expected"; break; - case 104: s = "\"::\" expected"; break; - case 105: s = "\"\\u2022\" expected"; break; - case 106: s = "??? expected"; break; - case 107: s = "invalid DatatypeDecl"; break; - case 108: s = "invalid ClassMemberDecl"; break; - case 109: s = "invalid FunctionDecl"; break; - case 110: s = "invalid MethodDecl"; break; + case 47: s = "\"call\" expected"; break; + case 48: s = "\"label\" expected"; break; + case 49: s = "\"break\" expected"; break; + case 50: s = "\"return\" expected"; break; + case 51: s = "\":=\" expected"; break; + case 52: s = "\"new\" expected"; break; + case 53: s = "\"[\" expected"; break; + case 54: s = "\"]\" expected"; break; + case 55: s = "\".\" expected"; break; + case 56: s = "\"choose\" expected"; break; + case 57: s = "\"havoc\" expected"; break; + case 58: s = "\"if\" expected"; break; + case 59: s = "\"else\" expected"; break; + case 60: s = "\"while\" expected"; break; + case 61: s = "\"invariant\" expected"; break; + case 62: s = "\"callXYZXYZ\" expected"; break; + case 63: s = "\"foreach\" expected"; break; + case 64: s = "\"in\" expected"; break; + case 65: s = "\"assert\" expected"; break; + case 66: s = "\"assume\" expected"; break; + case 67: s = "\"use\" expected"; break; + case 68: s = "\"print\" expected"; break; + case 69: s = "\"<==>\" expected"; break; + case 70: s = "\"\\u21d4\" expected"; break; + case 71: s = "\"==>\" expected"; break; + case 72: s = "\"\\u21d2\" expected"; break; + case 73: s = "\"&&\" expected"; break; + case 74: s = "\"\\u2227\" expected"; break; + case 75: s = "\"||\" expected"; break; + case 76: s = "\"\\u2228\" expected"; break; + case 77: s = "\"==\" expected"; break; + case 78: s = "\"<=\" expected"; break; + case 79: s = "\">=\" expected"; break; + case 80: s = "\"!=\" expected"; break; + case 81: s = "\"!!\" expected"; break; + case 82: s = "\"!in\" expected"; break; + case 83: s = "\"\\u2260\" expected"; break; + case 84: s = "\"\\u2264\" expected"; break; + case 85: s = "\"\\u2265\" expected"; break; + case 86: s = "\"+\" expected"; break; + case 87: s = "\"-\" expected"; break; + case 88: s = "\"/\" expected"; break; + case 89: s = "\"%\" expected"; break; + case 90: s = "\"!\" expected"; break; + case 91: s = "\"\\u00ac\" expected"; break; + case 92: s = "\"false\" expected"; break; + case 93: s = "\"true\" expected"; break; + case 94: s = "\"null\" expected"; break; + case 95: s = "\"this\" expected"; break; + case 96: s = "\"fresh\" expected"; break; + case 97: s = "\"allocated\" expected"; break; + case 98: s = "\"old\" expected"; break; + case 99: s = "\"then\" expected"; break; + case 100: s = "\"..\" expected"; break; + case 101: s = "\"forall\" expected"; break; + case 102: s = "\"\\u2200\" expected"; break; + case 103: s = "\"exists\" expected"; break; + case 104: s = "\"\\u2203\" expected"; break; + case 105: s = "\"::\" expected"; break; + case 106: s = "\"\\u2022\" expected"; break; + case 107: s = "??? expected"; break; + case 108: s = "invalid DatatypeDecl"; break; + case 109: s = "invalid ClassMemberDecl"; break; + case 110: s = "invalid FunctionDecl"; break; case 111: s = "invalid MethodDecl"; break; - case 112: s = "invalid TypeAndToken"; break; - case 113: s = "invalid MethodSpec"; break; + case 112: s = "invalid MethodDecl"; break; + case 113: s = "invalid TypeAndToken"; break; case 114: s = "invalid MethodSpec"; break; - case 115: s = "invalid ReferenceType"; break; - case 116: s = "invalid FunctionSpec"; break; - case 117: s = "invalid FunctionBody"; break; - case 118: s = "invalid PossiblyWildFrameExpression"; break; - case 119: s = "invalid PossiblyWildExpression"; break; - case 120: s = "invalid MatchOrExpr"; break; - case 121: s = "invalid Stmt"; break; - case 122: s = "invalid OneStmt"; break; - case 123: s = "invalid IfStmt"; break; - case 124: s = "invalid IfStmt"; break; - case 125: s = "invalid WhileStmt"; break; - case 126: s = "invalid ForeachStmt"; break; - case 127: s = "invalid AssignRhs"; break; - case 128: s = "invalid SelectExpression"; break; - case 129: s = "invalid Guard"; break; - case 130: s = "invalid CallStmtSubExpr"; break; - case 131: s = "invalid AttributeArg"; break; - case 132: s = "invalid EquivOp"; break; - case 133: s = "invalid ImpliesOp"; break; - case 134: s = "invalid AndOp"; break; - case 135: s = "invalid OrOp"; break; - case 136: s = "invalid RelOp"; break; - case 137: s = "invalid AddOp"; break; - case 138: s = "invalid UnaryExpression"; break; - case 139: s = "invalid MulOp"; break; - case 140: s = "invalid NegOp"; break; - case 141: s = "invalid EndlessExpression"; break; - case 142: s = "invalid ConstAtomExpression"; break; - case 143: s = "invalid QuantifierGuts"; break; - case 144: s = "invalid ObjectExpression"; break; - case 145: s = "invalid SelectOrCallSuffix"; break; - case 146: s = "invalid SelectOrCallSuffix"; break; - case 147: s = "invalid SelectOrCallSuffix"; break; - case 148: s = "invalid Forall"; break; - case 149: s = "invalid Exists"; break; - case 150: s = "invalid AttributeOrTrigger"; break; - case 151: s = "invalid QSep"; break; + case 115: s = "invalid MethodSpec"; break; + case 116: s = "invalid ReferenceType"; break; + case 117: s = "invalid FunctionSpec"; break; + case 118: s = "invalid FunctionBody"; break; + case 119: s = "invalid PossiblyWildFrameExpression"; break; + case 120: s = "invalid PossiblyWildExpression"; break; + case 121: s = "invalid MatchOrExpr"; break; + case 122: s = "invalid Stmt"; break; + case 123: s = "invalid OneStmt"; break; + case 124: s = "invalid UpdateStmt"; break; + case 125: s = "invalid IfStmt"; break; + case 126: s = "invalid IfStmt"; break; + case 127: s = "invalid WhileStmt"; break; + case 128: s = "invalid ForeachStmt"; break; + case 129: s = "invalid Lhs"; break; + case 130: s = "invalid Rhs"; break; + case 131: s = "invalid AssignRhs"; break; + case 132: s = "invalid SelectExpression"; break; + case 133: s = "invalid Guard"; break; + case 134: s = "invalid CallStmtSubExpr"; break; + case 135: s = "invalid AttributeArg"; break; + case 136: s = "invalid EquivOp"; break; + case 137: s = "invalid ImpliesOp"; break; + case 138: s = "invalid AndOp"; break; + case 139: s = "invalid OrOp"; break; + case 140: s = "invalid RelOp"; break; + case 141: s = "invalid AddOp"; break; + case 142: s = "invalid UnaryExpression"; break; + case 143: s = "invalid MulOp"; break; + case 144: s = "invalid NegOp"; break; + case 145: s = "invalid EndlessExpression"; break; + case 146: s = "invalid ConstAtomExpression"; break; + case 147: s = "invalid QuantifierGuts"; break; + case 148: s = "invalid ObjectExpression"; break; + case 149: s = "invalid SelectOrCallSuffix"; break; + case 150: s = "invalid SelectOrCallSuffix"; break; + case 151: s = "invalid SelectOrCallSuffix"; break; + case 152: s = "invalid Forall"; break; + case 153: s = "invalid Exists"; break; + case 154: s = "invalid AttributeOrTrigger"; break; + case 155: s = "invalid QSep"; break; default: s = "error " + n; break; } diff --git a/Dafny/Printer.cs b/Dafny/Printer.cs index 6a6cf8a8..e9a49ebc 100644 --- a/Dafny/Printer.cs +++ b/Dafny/Printer.cs @@ -470,7 +470,7 @@ namespace Microsoft.Dafny { } wr.Write(" := "); } - if (!(s.Receiver is ThisExpr)) { + if (!(s.Receiver is ImplicitThisExpr)) { PrintExpr(s.Receiver, 0x70, false, false, -1); wr.Write("."); } @@ -584,8 +584,24 @@ namespace Microsoft.Dafny { } } Indent(indent); - wr.WriteLine("}"); - + wr.Write("}"); + + } else if (stmt is UpdateStmt) { + var s = (UpdateStmt)stmt; + string sep = ""; + foreach (var lhs in s.Lhss) { + wr.Write(sep); + PrintExpression(lhs); + sep = ", "; + } + sep = " := "; + foreach (var rhs in s.Rhss) { + wr.Write(sep); + PrintDeterminedRhs(rhs); + sep = ", "; + } + wr.Write(";"); + } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement } @@ -829,12 +845,12 @@ namespace Microsoft.Dafny { FunctionCallExpr e = (FunctionCallExpr)expr; // determine if parens are needed int opBindingStrength = 0x70; - bool parensNeeded = !(e.Receiver is ThisExpr) && + bool parensNeeded = !(e.Receiver is ImplicitThisExpr) && opBindingStrength < contextBindingStrength || (fragileContext && opBindingStrength == contextBindingStrength); if (parensNeeded) { wr.Write("("); } - if (!(e.Receiver is ThisExpr)) { + if (!(e.Receiver is ImplicitThisExpr)) { PrintExpr(e.Receiver, opBindingStrength, false, false, -1); wr.Write("."); } diff --git a/Dafny/Resolver.cs b/Dafny/Resolver.cs index 6165c9a5..d0367502 100644 --- a/Dafny/Resolver.cs +++ b/Dafny/Resolver.cs @@ -537,12 +537,13 @@ namespace Microsoft.Dafny { } } - void ResolveAttributeArgs(List/*!*/ args, bool twoState, bool specContext) { + void ResolveAttributeArgs(List/*!*/ args, bool twoState, bool allowGhostFeatures) { Contract.Requires(args != null); + Contract.Requires(allowGhostFeatures); foreach (Attributes.Argument aa in args) { Contract.Assert(aa != null); if (aa.E != null) { - ResolveExpression(aa.E, twoState, specContext); + ResolveExpression(aa.E, twoState, allowGhostFeatures); } } } @@ -634,7 +635,10 @@ namespace Microsoft.Dafny { } if (f.Body != null) { List matchVarContext = new List(f.Formals); - ResolveExpression(f.Body, false, f.IsGhost, matchVarContext); + ResolveExpression(f.Body, false, true, matchVarContext); + if (!f.IsGhost) { + CheckIsNonGhost(f.Body); + } 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); @@ -1144,7 +1148,7 @@ namespace Microsoft.Dafny { } else if (stmt is PrintStmt) { PrintStmt s = (PrintStmt)stmt; - ResolveAttributeArgs(s.Args, false, false); + ResolveAttributeArgs(s.Args, false, true); 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)"); } @@ -1167,21 +1171,120 @@ namespace Microsoft.Dafny { if (specContextOnly) { Error(stmt, "return 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 if (stmt is UpdateStmt) { + var s = (UpdateStmt)stmt; + int prevErrorCount = ErrorCount; + // First, resolve all LHS's and expression-looking RHS's. When resolving these, allow ghosts for now, but enforce restrictions later. + foreach (var lhs in s.Lhss) { + if (lhs is SeqSelectExpr) { + ResolveSeqSelectExpr((SeqSelectExpr)lhs, true, true, true); + } else { + ResolveExpression(lhs, true, true); + } + } + IToken firstEffectfulRhs = null; + CallRhs callRhs = null; + foreach (var rhs in s.Rhss) { + bool isEffectful; + if (rhs is TypeRhs) { + ResolveTypeRhs((TypeRhs)rhs, stmt, specContextOnly, method); + isEffectful = true; + } else { + var er = (ExprRhs)rhs; + if (er.Expr is IdentifierSequence) { + var cRhs = ResolveIdentifierSequence((IdentifierSequence)er.Expr, true, true, true); + isEffectful = cRhs != null; + callRhs = callRhs ?? cRhs; + } else if (er.Expr is FunctionCallExpr) { + var cRhs = ResolveFunctionCallExpr((FunctionCallExpr)er.Expr, true, true, true); + isEffectful = cRhs != null; + callRhs = callRhs ?? cRhs; + } else { + ResolveExpression(er.Expr, true, true); + isEffectful = false; + } + } + if (isEffectful && firstEffectfulRhs == null) { + firstEffectfulRhs = rhs.Tok; + } + } + // check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification) + Dictionary lhsNameSet = new Dictionary(); + foreach (var lhs in s.Lhss) { + var ie = lhs.Resolved as IdentifierExpr; + if (ie != null) { + if (lhsNameSet.ContainsKey(ie.Name)) { + Error(s, "Duplicate variable in left-hand side of call statement: {0}", ie.Name); + } else { + lhsNameSet.Add(ie.Name, null); + } + } + } + // figure out what kind of UpdateStmt this is + if (firstEffectfulRhs == null) { + if (s.Lhss.Count == 0) { + Contract.Assert(s.Rhss.Count == 1); // guaranteed by the parser + Error(s, "expected method call, found expression"); + } else if (s.Lhss.Count != s.Rhss.Count) { + Error(s, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, s.Rhss.Count); + } else if (ErrorCount == prevErrorCount) { + for (int i = 0; i < s.Lhss.Count; i++) { + var a = new AssignStmt(s.Tok, s.Lhss[i].Resolved, s.Rhss[i]); + s.ResolvedStatements.Add(a); + } + } + } else { + // if there was an effectful RHS, that must be the only RHS + if (s.Rhss.Count != 1) { + Error(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS"); + } else if (callRhs == null) { + // must be a single TypeRhs + if (s.Lhss.Count != 1) { + Contract.Assert(2 <= s.Lhss.Count); // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs) + Error(s.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", s.Lhss.Count, s.Rhss.Count); + } else if (ErrorCount == prevErrorCount) { + var a = new AssignStmt(s.Tok, s.Lhss[0].Resolved, s.Rhss[0]); + s.ResolvedStatements.Add(a); + } + } else { + // a call statement + if (ErrorCount == prevErrorCount) { +#if !FULL_LHS_SUPPORT_FOR_CALLS + var idLhss = new List(); + var autos = new List(); + foreach (var ll in s.Lhss) { + var ie = (IdentifierExpr)ll.Resolved; // TODO: the CallStmt should handle all LHS's, not just identifier expressions + Contract.Assert(ie != null); + idLhss.Add(ie); + } +#endif + var a = new CallStmt(s.Tok, autos, idLhss, callRhs.Receiver, callRhs.MethodName, callRhs.Args); + s.ResolvedStatements.Add(a); + } + } + } + + foreach (var a in s.ResolvedStatements) { + ResolveStatement(a, specContextOnly, method); + } + } else if (stmt is AssignStmt) { AssignStmt s = (AssignStmt)stmt; int prevErrorCount = ErrorCount; if (s.Lhs is SeqSelectExpr) { - ResolveSeqSelectExpr((SeqSelectExpr)s.Lhs, true, false, true); + ResolveSeqSelectExpr((SeqSelectExpr)s.Lhs, true, true, true); // allow ghosts for now, tighted up below } else { - ResolveExpression(s.Lhs, true, true); // allow ghosts for now, but see FieldSelectExpr LHS case below + ResolveExpression(s.Lhs, true, true); // allow ghosts for now, tighted up below } bool lhsResolvedSuccessfully = ErrorCount == 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; - if (s.Lhs is IdentifierExpr) { - IVariable var = ((IdentifierExpr)s.Lhs).Var; + 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 { @@ -1193,8 +1296,8 @@ namespace Microsoft.Dafny { 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)"); } } - } else if (s.Lhs is FieldSelectExpr) { - FieldSelectExpr fse = (FieldSelectExpr)s.Lhs; + } else if (lhs is FieldSelectExpr) { + var fse = (FieldSelectExpr)lhs; if (fse.Field != null) { // otherwise, an error was reported above lvalueIsGhost = fse.Field.IsGhost; if (!lvalueIsGhost) { @@ -1212,24 +1315,24 @@ namespace Microsoft.Dafny { Error(stmt, "LHS of assignment does not denote a mutable field"); } } - } else if (s.Lhs is SeqSelectExpr) { - SeqSelectExpr lhs = (SeqSelectExpr)s.Lhs; + } else if (lhs is SeqSelectExpr) { + var slhs = (SeqSelectExpr)lhs; // LHS is fine, provided the "sequence" is really an array if (lhsResolvedSuccessfully) { - Contract.Assert(lhs.Seq.Type != null); + Contract.Assert(slhs.Seq.Type != null); Type elementType = new InferredTypeProxy(); - if (!UnifyTypes(lhs.Seq.Type, builtIns.ArrayType(1, elementType))) { - Error(lhs.Seq, "LHS of array assignment must denote an array element (found {0})", lhs.Seq.Type); + if (!UnifyTypes(slhs.Seq.Type, builtIns.ArrayType(1, elementType))) { + Error(slhs.Seq, "LHS of array assignment must denote an array element (found {0})", slhs.Seq.Type); } 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)"); } - if (!lhs.SelectOne && !(s.Rhs is ExprRhs)) { + if (!slhs.SelectOne && !(s.Rhs is ExprRhs)) { Error(stmt, "Assignment to range of array elements must have a simple expression RHS; try using a temporary local variable"); } } - } else if (s.Lhs is MultiSelectExpr) { + } 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)"); } @@ -1240,22 +1343,37 @@ namespace Microsoft.Dafny { s.IsGhost = lvalueIsGhost; Type lhsType = s.Lhs.Type; - if (s.Lhs is SeqSelectExpr && !((SeqSelectExpr)s.Lhs).SelectOne) { + if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) { Contract.Assert(lhsType.IsArrayType); lhsType = UserDefinedType.ArrayElementType(lhsType); } if (s.Rhs is ExprRhs) { ExprRhs rr = (ExprRhs)s.Rhs; - ResolveExpression(rr.Expr, true, lvalueIsGhost); + ResolveExpression(rr.Expr, true, true); + if (!lvalueIsGhost) { + CheckIsNonGhost(rr.Expr); + } 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, s.Lhs.Type); + Error(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, method); + 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, s.Lhs.Type); + Error(stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType); } } else if (s.Rhs is HavocRhs) { // nothing else to do @@ -1273,7 +1391,10 @@ namespace Microsoft.Dafny { Type rhsType; if (s.Rhs is ExprRhs) { ExprRhs rr = (ExprRhs)s.Rhs; - ResolveExpression(rr.Expr, true, s.IsGhost); + ResolveExpression(rr.Expr, true, true); + if (!s.IsGhost) { + CheckIsNonGhost(rr.Expr); + } Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression rhsType = rr.Expr.Type; } else if (s.Rhs is TypeRhs) { @@ -1551,7 +1672,7 @@ namespace Microsoft.Dafny { // resolve receiver, unless told otherwise if (receiverType == null) { - ResolveReceiver(s.Receiver, true, false); + ResolveReceiver(s.Receiver, true, true); Contract.Assert(s.Receiver.Type != null); // follows from postcondition of ResolveExpression receiverType = s.Receiver.Type; } @@ -1592,10 +1713,16 @@ namespace Microsoft.Dafny { } } // resolve arguments + if (!s.IsGhost) { + CheckIsNonGhost(s.Receiver); + } int j = 0; foreach (Expression e in s.Args) { bool allowGhost = s.IsGhost || callee == null || callee.Ins.Count <= j || callee.Ins[j].IsGhost; - ResolveExpression(e, true, allowGhost); + ResolveExpression(e, true, true); + if (!allowGhost) { + CheckIsNonGhost(e); + } j++; } @@ -1684,34 +1811,36 @@ namespace Microsoft.Dafny { for (; 0 < labelsToPop; labelsToPop--) { labeledStatements.PopMarker(); } } - Type ResolveTypeRhs(TypeRhs rr, Statement stmt, bool specContext, Method method) { + Type ResolveTypeRhs(TypeRhs rr, Statement stmt, bool specContextOnly, Method method) { Contract.Requires(rr != null); Contract.Requires(stmt != null); Contract.Requires(method != null); Contract.Ensures(Contract.Result() != null); - ResolveType(stmt.Tok, rr.EType); - if (rr.ArrayDimensions == null) { - if (!rr.EType.IsRefType) { - Error(stmt, "new can be applied only to reference types (got {0})", rr.EType); - } else if (rr.InitCall != null) { - ResolveCallStmt(rr.InitCall, specContext, method, rr.EType); - } - rr.Type = rr.EType; - } else { - int i = 0; - if (rr.EType.IsSubrangeType) { - Error(stmt, "sorry, cannot instantiate 'array' type with a subrange type"); - } - foreach (Expression dim in rr.ArrayDimensions) { - Contract.Assert(dim != null); - ResolveExpression(dim, true, specContext); - if (!UnifyTypes(dim.Type, Type.Int)) { - Error(stmt, "new must use an integer expression for the array size (got {0} for index {1})", dim.Type, i); + if (rr.Type == null) { + ResolveType(stmt.Tok, rr.EType); + if (rr.ArrayDimensions == null) { + if (!rr.EType.IsRefType) { + Error(stmt, "new can be applied only to reference types (got {0})", rr.EType); + } else if (rr.InitCall != null) { + ResolveCallStmt(rr.InitCall, specContextOnly, method, rr.EType); } - i++; + rr.Type = rr.EType; + } else { + int i = 0; + if (rr.EType.IsSubrangeType) { + Error(stmt, "sorry, cannot instantiate 'array' type with a subrange type"); + } + foreach (Expression dim in rr.ArrayDimensions) { + Contract.Assert(dim != null); + ResolveExpression(dim, true, true); + if (!UnifyTypes(dim.Type, Type.Int)) { + Error(stmt, "new must use an integer expression for the array size (got {0} for index {1})", dim.Type, i); + } + i++; + } + rr.Type = builtIns.ArrayType(rr.ArrayDimensions.Count, rr.EType); } - rr.Type = builtIns.ArrayType(rr.ArrayDimensions.Count, rr.EType); } return rr.Type; } @@ -1824,11 +1953,13 @@ namespace Microsoft.Dafny { /// /// "twoState" implies that "old" and "fresh" expressions are allowed /// - void ResolveExpression(Expression expr, bool twoState, bool specContext) { - ResolveExpression(expr, twoState, specContext, null); + void ResolveExpression(Expression expr, bool twoState, bool allowGhostFeatures) { + Contract.Requires(allowGhostFeatures); + ResolveExpression(expr, twoState, allowGhostFeatures, null); } - void ResolveExpression(Expression expr, bool twoState, bool specContext, List matchVarContext) { + void ResolveExpression(Expression expr, bool twoState, bool allowGhostFeatures, List matchVarContext) { + Contract.Requires(allowGhostFeatures); Contract.Requires(expr != null); Contract.Requires(currentClass != null); Contract.Ensures(expr.Type != null); @@ -1844,13 +1975,13 @@ namespace Microsoft.Dafny { if (expr is ParensExpression) { var e = (ParensExpression)expr; - ResolveExpression(e.E, twoState, specContext); + ResolveExpression(e.E, twoState, allowGhostFeatures); e.ResolvedExpression = e.E; e.Type = e.E.Type; } else if (expr is IdentifierSequence) { var e = (IdentifierSequence)expr; - ResolveIdentifierSequence(e, twoState, specContext, false); + ResolveIdentifierSequence(e, twoState, allowGhostFeatures, false); } else if (expr is LiteralExpr) { LiteralExpr e = (LiteralExpr)expr; @@ -1866,7 +1997,7 @@ namespace Microsoft.Dafny { } else if (expr is ThisExpr) { if (!scope.AllowInstance) { - Error(expr, "'this' is not allowed in a 'class' context"); + Error(expr, "'this' is not allowed in a 'static' context"); } expr.Type = GetThisType(expr.tok, currentClass); // do this regardless of scope.AllowInstance, for better error reporting @@ -1877,7 +2008,7 @@ namespace Microsoft.Dafny { Error(expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name); } else { expr.Type = e.Var.Type; - if (!specContext && e.Var.IsGhost) { + if (!allowGhostFeatures && e.Var.IsGhost) { Error(expr, "ghost variables are allowed only in specification contexts"); } } @@ -1916,7 +2047,7 @@ namespace Microsoft.Dafny { int j = 0; foreach (Expression arg in dtv.Arguments) { Formal formal = ctor != null && j < ctor.Formals.Count ? ctor.Formals[j] : null; - ResolveExpression(arg, twoState, specContext || (formal != null && formal.IsGhost)); + ResolveExpression(arg, twoState, allowGhostFeatures || (formal != null && formal.IsGhost)); Contract.Assert(arg.Type != null); // follows from postcondition of ResolveExpression if (formal != null) { Type st = SubstType(formal.Type, subst); @@ -1932,7 +2063,7 @@ namespace Microsoft.Dafny { DisplayExpression e = (DisplayExpression)expr; Type elementType = new InferredTypeProxy(); foreach (Expression ee in e.Elements) { - ResolveExpression(ee, twoState, specContext); + ResolveExpression(ee, twoState, allowGhostFeatures); 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); @@ -1946,7 +2077,7 @@ namespace Microsoft.Dafny { } else if (expr is FieldSelectExpr) { FieldSelectExpr e = (FieldSelectExpr)expr; - ResolveExpression(e.Obj, twoState, specContext); + ResolveExpression(e.Obj, twoState, allowGhostFeatures); Contract.Assert(e.Obj.Type != null); // follows from postcondition of ResolveExpression UserDefinedType ctype; MemberDecl member = ResolveMember(expr.tok, e.Obj.Type, e.FieldName, out ctype); @@ -1966,19 +2097,19 @@ namespace Microsoft.Dafny { subst.Add(ctype.ResolvedClass.TypeArgs[i], ctype.TypeArgs[i]); } e.Type = SubstType(e.Field.Type, subst); - if (!specContext && e.Field.IsGhost) { + if (!allowGhostFeatures && e.Field.IsGhost) { Error(expr, "ghost fields are allowed only in specification contexts"); } } } else if (expr is SeqSelectExpr) { SeqSelectExpr e = (SeqSelectExpr)expr; - ResolveSeqSelectExpr(e, twoState, specContext, false); + ResolveSeqSelectExpr(e, twoState, allowGhostFeatures, false); } else if (expr is MultiSelectExpr) { MultiSelectExpr e = (MultiSelectExpr)expr; - ResolveExpression(e.Array, twoState, specContext); + ResolveExpression(e.Array, twoState, allowGhostFeatures); Contract.Assert(e.Array.Type != null); // follows from postcondition of ResolveExpression Type elementType = new InferredTypeProxy(); if (!UnifyTypes(e.Array.Type, builtIns.ArrayType(e.Indices.Count, elementType))) { @@ -1987,7 +2118,7 @@ namespace Microsoft.Dafny { int i = 0; foreach (Expression idx in e.Indices) { Contract.Assert(idx != null); - ResolveExpression(idx, twoState, specContext); + ResolveExpression(idx, twoState, allowGhostFeatures); Contract.Assert(idx.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(idx.Type, Type.Int)) { Error(idx, "array selection requires integer indices (got {0} for index {1})", idx.Type, i); @@ -1999,19 +2130,19 @@ namespace Microsoft.Dafny { } else if (expr is SeqUpdateExpr) { SeqUpdateExpr e = (SeqUpdateExpr)expr; bool seqErr = false; - ResolveExpression(e.Seq, twoState, specContext); + ResolveExpression(e.Seq, twoState, allowGhostFeatures); Contract.Assert(e.Seq.Type != null); // follows from postcondition of ResolveExpression Type elementType = new InferredTypeProxy(); if (!UnifyTypes(e.Seq.Type, new SeqType(elementType))) { Error(expr, "sequence update requires a sequence (got {0})", e.Seq.Type); seqErr = true; } - ResolveExpression(e.Index, twoState, specContext); + ResolveExpression(e.Index, twoState, allowGhostFeatures); 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); } - ResolveExpression(e.Value, twoState, specContext); + ResolveExpression(e.Value, twoState, allowGhostFeatures); 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); @@ -2022,96 +2153,26 @@ namespace Microsoft.Dafny { } else if (expr is FunctionCallExpr) { FunctionCallExpr e = (FunctionCallExpr)expr; - ResolveReceiver(e.Receiver, twoState, specContext); - Contract.Assert(e.Receiver.Type != null); // follows from postcondition of ResolveExpression - UserDefinedType ctype; - MemberDecl member = ResolveMember(expr.tok, e.Receiver.Type, e.Name, out ctype); - if (member == null) { - // error has already been reported by ResolveMember - } else if (!(member is Function)) { - Error(expr, "member {0} in class {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name); - } else { - Function function = (Function)member; - e.Function = function; - if (e.Receiver is StaticReceiverExpr && !function.IsStatic) { - Error(expr, "an instance function must be selected via an object, not just a class name"); - } - if (!specContext && function.IsGhost) { - Error(expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')"); - } - if (function.Formals.Count != e.Args.Count) { - Error(expr, "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 (!scope.AllowInstance && !function.IsStatic && e.Receiver is ThisExpr) { - // The call really needs an instance, but that instance is given as 'this', which is not - // available in this context. In most cases, occurrences of 'this' inside e.Receiver would - // have been caught in the recursive call to resolve e.Receiver, but not the specific case - // of e.Receiver being 'this' (explicitly or implicitly), for that case needs to be allowed - // in the event that a class function calls another class 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"); - } - // build the type substitution map - Dictionary subst = new Dictionary(); - for (int i = 0; i < ctype.TypeArgs.Count; i++) { - subst.Add(cce.NonNull(ctype.ResolvedClass).TypeArgs[i], ctype.TypeArgs[i]); - } - foreach (TypeParameter p in function.TypeArgs) { - subst.Add(p, new ParamTypeProxy(p)); - } - // type check the arguments - for (int i = 0; i < function.Formals.Count; i++) { - Expression farg = e.Args[i]; - ResolveExpression(farg, twoState, specContext); - Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression - Type s = SubstType(function.Formals[i].Type, subst); - if (!UnifyTypes(farg.Type, s)) { - Error(expr, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); - } - } - expr.Type = SubstType(function.ResultType, subst); - } - - // Resolution termination check - if (currentFunction != null && currentFunction.EnclosingClass != null && function.EnclosingClass != null) { - ModuleDecl callerModule = currentFunction.EnclosingClass.Module; - ModuleDecl calleeModule = function.EnclosingClass.Module; - if (callerModule == calleeModule) { - // intra-module call; this is allowed; add edge in module's call graph - callerModule.CallGraph.AddEdge(currentFunction, function); - if (currentFunction == function) { - currentFunction.IsRecursive = true; // self recursion (mutual recursion is determined elsewhere) - } - } else if (calleeModule.IsDefaultModule) { - // all is fine: everything implicitly imports the default module - } else if (importGraph.Reaches(callerModule, calleeModule)) { - // all is fine: the callee is downstream of the caller - } else { - Error(expr, "inter-module calls must follow the module import relation (so module {0} must transitively import {1})", callerModule.Name, calleeModule.Name); - } - } - } + ResolveFunctionCallExpr(e, twoState, allowGhostFeatures, false); } else if (expr is OldExpr) { OldExpr e = (OldExpr)expr; if (!twoState) { Error(expr, "old expressions are not allowed in this context"); - } else if (!specContext) { + } else if (!allowGhostFeatures) { Error(expr, "old expressions are allowed only in specification and ghost contexts"); } - ResolveExpression(e.E, twoState, specContext); + ResolveExpression(e.E, twoState, allowGhostFeatures); expr.Type = e.E.Type; } else if (expr is FreshExpr) { FreshExpr e = (FreshExpr)expr; if (!twoState) { Error(expr, "fresh expressions are not allowed in this context"); - } else if (!specContext) { + } else if (!allowGhostFeatures) { Error(expr, "fresh expressions are allowed only in specification and ghost contexts"); } - ResolveExpression(e.E, twoState, specContext); + ResolveExpression(e.E, twoState, allowGhostFeatures); // the type of e.E must be either an object or a collection of objects Type t = e.E.Type; Contract.Assert(t != null); // follows from postcondition of ResolveExpression @@ -2129,8 +2190,8 @@ namespace Microsoft.Dafny { } else if (expr is AllocatedExpr) { AllocatedExpr e = (AllocatedExpr)expr; - ResolveExpression(e.E, twoState, specContext); - if (!specContext) { + ResolveExpression(e.E, twoState, allowGhostFeatures); + if (!allowGhostFeatures) { Error(expr, "allocated expressions are allowed only in specification and ghost contexts"); } // e.E can be of any type @@ -2138,7 +2199,7 @@ namespace Microsoft.Dafny { } else if (expr is UnaryExpr) { UnaryExpr e = (UnaryExpr)expr; - ResolveExpression(e.E, twoState, specContext); + ResolveExpression(e.E, twoState, allowGhostFeatures); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression switch (e.Op) { case UnaryExpr.Opcode.Not: @@ -2166,9 +2227,9 @@ namespace Microsoft.Dafny { } else if (expr is BinaryExpr) { BinaryExpr e = (BinaryExpr)expr; - ResolveExpression(e.E0, twoState, specContext); + ResolveExpression(e.E0, twoState, allowGhostFeatures); Contract.Assert(e.E0.Type != null); // follows from postcondition of ResolveExpression - ResolveExpression(e.E1, twoState, specContext); + ResolveExpression(e.E1, twoState, allowGhostFeatures); Contract.Assert(e.E1.Type != null); // follows from postcondition of ResolveExpression switch (e.Op) { case BinaryExpr.Opcode.Iff: @@ -2210,7 +2271,7 @@ namespace Microsoft.Dafny { if (!UnifyTypes(e.E1.Type, new DatatypeProxy())) { Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); } - if (!specContext) { + if (!allowGhostFeatures) { Error(expr, "rank comparisons are allowed only in specification and ghost contexts"); } expr.Type = Type.Bool; @@ -2242,7 +2303,7 @@ namespace Microsoft.Dafny { if (!UnifyTypes(e.E1.Type, new DatatypeProxy())) { Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); } - if (!specContext) { + if (!allowGhostFeatures) { Error(expr, "rank comparisons are allowed only in specification and ghost contexts"); } expr.Type = Type.Bool; @@ -2300,13 +2361,13 @@ namespace Microsoft.Dafny { ResolveType(v.tok, v.Type); } if (e.Range != null) { - ResolveExpression(e.Range, twoState, specContext); + ResolveExpression(e.Range, twoState, allowGhostFeatures); 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); } } - ResolveExpression(e.Term, twoState, specContext); + ResolveExpression(e.Term, twoState, allowGhostFeatures); 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); @@ -2319,7 +2380,11 @@ namespace Microsoft.Dafny { expr.Type = Type.Bool; if (prevErrorCount == ErrorCount) { - e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, specContext ? null : "quantifiers in non-ghost contexts must be compilable"); + var missingBounds = new List(); + e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, missingBounds); + if (missingBounds.Count != 0) { + e.MissingBounds = missingBounds; + } } } else if (expr is SetComprehension) { @@ -2332,12 +2397,12 @@ namespace Microsoft.Dafny { } ResolveType(v.tok, v.Type); } - ResolveExpression(e.Range, twoState, specContext); + ResolveExpression(e.Range, twoState, allowGhostFeatures); 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); } - ResolveExpression(e.Term, twoState, specContext); + ResolveExpression(e.Term, twoState, allowGhostFeatures); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression ResolveAttributes(e.Attributes, twoState); @@ -2345,7 +2410,11 @@ namespace Microsoft.Dafny { expr.Type = new SetType(e.Term.Type); if (prevErrorCount == ErrorCount) { - e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, "a set comprehension must produce a finite set"); + var missingBounds = new List(); + e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, missingBounds); + if (missingBounds.Count != 0) { + e.MissingBounds = missingBounds; + } } } else if (expr is WildcardExpr) { @@ -2353,11 +2422,11 @@ namespace Microsoft.Dafny { } else if (expr is ITEExpr) { ITEExpr e = (ITEExpr)expr; - ResolveExpression(e.Test, twoState, specContext); + ResolveExpression(e.Test, twoState, allowGhostFeatures); Contract.Assert(e.Test.Type != null); // follows from postcondition of ResolveExpression - ResolveExpression(e.Thn, twoState, specContext); + ResolveExpression(e.Thn, twoState, allowGhostFeatures); Contract.Assert(e.Thn.Type != null); // follows from postcondition of ResolveExpression - ResolveExpression(e.Els, twoState, specContext); + ResolveExpression(e.Els, twoState, allowGhostFeatures); 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); @@ -2371,7 +2440,7 @@ namespace Microsoft.Dafny { } else if (expr is MatchExpr) { MatchExpr me = (MatchExpr)expr; Contract.Assert(!twoState); // currently, match expressions are allowed only at the outermost level of function bodies - ResolveExpression(me.Source, twoState, specContext); + ResolveExpression(me.Source, twoState, allowGhostFeatures); Contract.Assert(me.Source.Type != null); // follows from postcondition of ResolveExpression UserDefinedType sourceType = null; DatatypeDecl dtd = null; @@ -2448,7 +2517,7 @@ namespace Microsoft.Dafny { innerMatchVarContext.Remove(goodMatchVariable); // this variable is no longer available for matching } innerMatchVarContext.AddRange(mc.Arguments); - ResolveExpression(mc.Body, twoState, specContext, innerMatchVarContext); + ResolveExpression(mc.Body, twoState, allowGhostFeatures, innerMatchVarContext); 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); @@ -2478,11 +2547,173 @@ namespace Microsoft.Dafny { } } + /// + /// Generate an error for every non-ghost feature used in "expr". + /// Requires "expr" to have been successfully resolved. + /// + void CheckIsNonGhost(Expression expr) { + Contract.Requires(expr != null); + Contract.Requires(currentClass != null); + Contract.Requires(expr.Type != null); // this check approximates the requirement that "expr" be resolved + + if (expr is IdentifierExpr) { + IdentifierExpr e = (IdentifierExpr)expr; + if (e.Var != null && e.Var.IsGhost) { + Error(expr, "ghost variables are allowed only in specification contexts"); + return; + } + + } else if (expr is FieldSelectExpr) { + FieldSelectExpr e = (FieldSelectExpr)expr; + if (e.Field != null && e.Field.IsGhost) { + Error(expr, "ghost fields are allowed only in specification contexts"); + return; + } + + } else if (expr is FunctionCallExpr) { + FunctionCallExpr e = (FunctionCallExpr)expr; + if (e.Function != null && e.Function.IsGhost) { + Error(expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')"); + return; + } + + } else if (expr is OldExpr) { + Error(expr, "old expressions are allowed only in specification and ghost contexts"); + return; + + } else if (expr is FreshExpr) { + Error(expr, "fresh expressions are allowed only in specification and ghost contexts"); + return; + + } else if (expr is AllocatedExpr) { + Error(expr, "allocated expressions are allowed only in specification and ghost contexts"); + return; + + } else if (expr is BinaryExpr) { + BinaryExpr e = (BinaryExpr)expr; + switch (e.ResolvedOp) { + case BinaryExpr.ResolvedOpcode.RankGt: + case BinaryExpr.ResolvedOpcode.RankLt: + Error(expr, "rank comparisons are allowed only in specification and ghost contexts"); + return; + default: + break; + } + + } else if (expr is QuantifierExpr) { + QuantifierExpr 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); + } + return; + } + + } else if (expr is SetComprehension) { + var e = (SetComprehension)expr; + if (e.MissingBounds != null) { + foreach (var bv in e.MissingBounds) { + Error(expr, "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); + } + return; + } + } + + foreach (var ee in expr.SubExpressions) { + CheckIsNonGhost(ee); + } + } + + /// + /// If "!allowMethodCall" or if what is being called does not refer to a method, resolves "e" and returns "null". + /// Otherwise (that is, if "allowMethodCall" and what is being called refers to a method), resolves the receiver + /// of "e" but NOT the arguments, and returns a CallRhs corresponding to the call. + /// + CallRhs ResolveFunctionCallExpr(FunctionCallExpr e, bool twoState, bool allowGhostFeatures, bool allowMethodCall) { + Contract.Requires(allowGhostFeatures); + ResolveReceiver(e.Receiver, twoState, allowGhostFeatures); + Contract.Assert(e.Receiver.Type != null); // follows from postcondition of ResolveExpression + UserDefinedType ctype; + MemberDecl member = ResolveMember(e.tok, e.Receiver.Type, e.Name, out ctype); + if (member == null) { + // error has already been reported by ResolveMember + } else if (allowMethodCall && member is Method) { + // it's a method + return new CallRhs(e.tok, e.Receiver, e.Name, e.Args); + } else if (!(member is Function)) { + Error(e, "member {0} in class {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name); + } else { + Function function = (Function)member; + e.Function = function; + if (e.Receiver is StaticReceiverExpr && !function.IsStatic) { + Error(e, "an instance function must be selected via an object, not just a class name"); + } + if (!allowGhostFeatures && function.IsGhost) { + Error(e, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')"); + } + if (function.Formals.Count != e.Args.Count) { + Error(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 (!scope.AllowInstance && !function.IsStatic && e.Receiver is ThisExpr) { + // The call really needs an instance, but that instance is given as 'this', which is not + // available in this context. In most cases, occurrences of 'this' inside e.Receiver would + // have been caught in the recursive call to resolve e.Receiver, but not the specific case + // of e.Receiver being 'this' (explicitly or implicitly), for that case needs to be allowed + // in the event that a class function calls another class 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"); + } + // build the type substitution map + Dictionary subst = new Dictionary(); + for (int i = 0; i < ctype.TypeArgs.Count; i++) { + subst.Add(cce.NonNull(ctype.ResolvedClass).TypeArgs[i], ctype.TypeArgs[i]); + } + foreach (TypeParameter p in function.TypeArgs) { + subst.Add(p, new ParamTypeProxy(p)); + } + // type check the arguments + for (int i = 0; i < function.Formals.Count; i++) { + Expression farg = e.Args[i]; + ResolveExpression(farg, twoState, allowGhostFeatures); + Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression + Type s = SubstType(function.Formals[i].Type, subst); + if (!UnifyTypes(farg.Type, s)) { + Error(e, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); + } + } + e.Type = SubstType(function.ResultType, subst); + } + + // Resolution termination check + if (currentFunction != null && currentFunction.EnclosingClass != null && function.EnclosingClass != null) { + ModuleDecl callerModule = currentFunction.EnclosingClass.Module; + ModuleDecl calleeModule = function.EnclosingClass.Module; + if (callerModule == calleeModule) { + // intra-module call; this is allowed; add edge in module's call graph + callerModule.CallGraph.AddEdge(currentFunction, function); + if (currentFunction == function) { + currentFunction.IsRecursive = true; // self recursion (mutual recursion is determined elsewhere) + } + } else if (calleeModule.IsDefaultModule) { + // all is fine: everything implicitly imports the default module + } else if (importGraph.Reaches(callerModule, calleeModule)) { + // all is fine: the callee is downstream of the caller + } else { + Error(e, "inter-module calls must follow the module import relation (so module {0} must transitively import {1})", callerModule.Name, calleeModule.Name); + } + } + } + return null; + } + /// /// If "!allowMethodCall", or if "e" does not designate a method call, resolves "e" and returns "null". /// Otherwise, resolves all sub-parts of "e" and returns a (resolved) CallRhs expression representing the call. /// - CallRhs ResolveIdentifierSequence(IdentifierSequence e, bool twoState, bool specContext, bool allowMethodCall) { + CallRhs ResolveIdentifierSequence(IdentifierSequence e, bool twoState, bool allowGhostFeatures, bool allowMethodCall) { + Contract.Requires(allowGhostFeatures); // Look up "id" as follows: // - local variable, parameter, or bound variable (if this clashes with something of interest, one can always rename the local variable locally) // - type name (class or datatype) @@ -2501,8 +2732,8 @@ namespace Microsoft.Dafny { if (scope.Find(id.val) != null) { // ----- root is a local variable, parameter, or bound variable r = new IdentifierExpr(id, id.val); - ResolveExpression(r, twoState, specContext); - r = ResolveSuffix(r, e, 1, twoState, specContext, allowMethodCall, out call); + ResolveExpression(r, twoState, allowGhostFeatures); + r = ResolveSuffix(r, e, 1, twoState, allowGhostFeatures, allowMethodCall, out call); } else if (classes.TryGetValue(id.val, out decl)) { if (e.Tokens.Count == 1 && e.Arguments == null) { @@ -2511,21 +2742,21 @@ namespace Microsoft.Dafny { Error(id, "name of type ('{0}') is used as a function", id.val); // resolve the arguments nonetheless foreach (var arg in e.Arguments) { - ResolveExpression(arg, twoState, specContext); + ResolveExpression(arg, twoState, allowGhostFeatures); } } else if (decl is ClassDecl) { // ----- root is a class var cd = (ClassDecl)decl; - r = ResolveSuffix(new StaticReceiverExpr(id, cd), e, 1, twoState, specContext, allowMethodCall, out call); + r = ResolveSuffix(new StaticReceiverExpr(id, cd), e, 1, twoState, allowGhostFeatures, allowMethodCall, out call); } else { // ----- root is a datatype var dt = (DatatypeDecl)decl; // otherwise, unexpected TopLevelDecl var args = (e.Tokens.Count == 2 ? e.Arguments : null) ?? new List(); r = new DatatypeValue(id, id.val, e.Tokens[1].val, args); - ResolveExpression(r, twoState, specContext); + ResolveExpression(r, twoState, allowGhostFeatures); if (e.Tokens.Count != 2) { - r = ResolveSuffix(r, e, 2, twoState, specContext, allowMethodCall, out call); + r = ResolveSuffix(r, e, 2, twoState, allowGhostFeatures, allowMethodCall, out call); } } @@ -2537,22 +2768,33 @@ namespace Microsoft.Dafny { } else { var args = (e.Tokens.Count == 1 ? e.Arguments : null) ?? new List(); r = new DatatypeValue(id, pair.Item1.EnclosingDatatype.Name, id.val, args); - ResolveExpression(r, twoState, specContext); + ResolveExpression(r, twoState, allowGhostFeatures); if (e.Tokens.Count != 1) { - r = ResolveSuffix(r, e, 1, twoState, specContext, allowMethodCall, out call); + r = ResolveSuffix(r, e, 1, twoState, allowGhostFeatures, allowMethodCall, out call); } } } else if (classMembers.TryGetValue(currentClass, out members) && members.TryGetValue(id.val, out member)) { // ----- field, function, or method - r = ResolveSuffix(new ImplicitThisExpr(id), e, 0, twoState, specContext, allowMethodCall, out call); + Expression receiver; + if (member.IsStatic) { + receiver = new StaticReceiverExpr(id, currentClass); + } else { + if (!scope.AllowInstance) { + Error(id, "'this' is not allowed in a 'static' context"); + // nevertheless, set "receiver" to a value so we can continue resolution + } + receiver = new ImplicitThisExpr(id); + receiver.Type = GetThisType(id, currentClass); // resolve here + } + r = ResolveSuffix(receiver, e, 0, twoState, allowGhostFeatures, allowMethodCall, out call); } else { Error(id, "unresolved identifier: {0}", id.val); // resolve arguments, if any if (e.Arguments != null) { foreach (var arg in e.Arguments) { - ResolveExpression(arg, twoState, specContext); + ResolveExpression(arg, twoState, allowGhostFeatures); } } } @@ -2571,7 +2813,8 @@ namespace Microsoft.Dafny { /// Except, if "allowMethodCall" is "true" and the would-be-returned value designates a method /// call, instead returns null and returns "call" as a non-null value. /// - Expression ResolveSuffix(Expression r, IdentifierSequence e, int p, bool twoState, bool specContext, bool allowMethodCall, out CallRhs call) { + Expression ResolveSuffix(Expression r, IdentifierSequence e, int p, bool twoState, bool allowGhostFeatures, bool allowMethodCall, out CallRhs call) { + Contract.Requires(allowGhostFeatures); Contract.Requires(r != null); Contract.Requires(e != null); Contract.Requires(0 <= p && p <= e.Tokens.Count); @@ -2582,7 +2825,7 @@ namespace Microsoft.Dafny { int nonCallArguments = e.Arguments == null ? e.Tokens.Count : e.Tokens.Count - 1; for (; p < nonCallArguments; p++) { r = new FieldSelectExpr(e.Tokens[p], r, e.Tokens[p].val); - ResolveExpression(r, twoState, specContext); + ResolveExpression(r, twoState, allowGhostFeatures); } if (p < e.Tokens.Count) { @@ -2590,21 +2833,25 @@ namespace Microsoft.Dafny { Dictionary members; MemberDecl member; - if (classMembers.TryGetValue(currentClass, out members) && members.TryGetValue(e.Tokens[p].val, out member) && member is Method) { + UserDefinedType receiverType = UserDefinedType.DenotesClass(r.Type); + if (allowMethodCall && + receiverType != null && + classMembers.TryGetValue((ClassDecl)receiverType.ResolvedClass, out members) && + members.TryGetValue(e.Tokens[p].val, out member) && + member is Method) { // method call = new CallRhs(e.Tokens[p], r, e.Tokens[p].val, e.Arguments); - // TODO: resolve call, and sometimes return an error message if a call is not allowed here r = null; } else { r = new FunctionCallExpr(e.Tokens[p], e.Tokens[p].val, r, e.Arguments); - ResolveExpression(r, twoState, specContext); + ResolveExpression(r, twoState, allowGhostFeatures); } } else if (e.Arguments != null) { Contract.Assert(p == e.Tokens.Count); Error(e.OpenParen, "non-function expression is called with parameters"); // resolve the arguments nonetheless foreach (var arg in e.Arguments) { - ResolveExpression(arg, twoState, specContext); + ResolveExpression(arg, twoState, allowGhostFeatures); } } return r; @@ -2612,18 +2859,23 @@ namespace Microsoft.Dafny { /// /// Tries to find a bounded pool for each of the bound variables "bvars" of "expr". If this process - /// fails, then "null" is returned and: - /// if "errorMessage" is non-null, then appropriate error messages are reported and "null" is returned; - /// if "errorMessage" is null, no error messages are reported. + /// fails, then "null" is returned and the bound variables for which the process fails are added to "missingBounds". /// Requires "e" to be successfully resolved. /// - List DiscoverBounds(IToken tok, List bvars, Expression expr, bool polarity, string errorMessage) { + List DiscoverBounds(IToken tok, List bvars, Expression expr, bool polarity, List missingBounds) { Contract.Requires(tok != null); Contract.Requires(bvars != null); + Contract.Requires(missingBounds != null); Contract.Requires(expr.Type != null); // a sanity check (but not a complete proof) that "e" has been resolved - Contract.Ensures(Contract.Result>().Count == bvars.Count); + Contract.Ensures( + (Contract.Result>() != null && + Contract.Result>().Count == bvars.Count && + Contract.OldValue(missingBounds.Count) == missingBounds.Count) || + (Contract.Result>() == null && + Contract.OldValue(missingBounds.Count) < missingBounds.Count)); var bounds = new List(); + bool foundError = false; for (int j = 0; j < bvars.Count; j++) { var bv = bvars[j]; if (bv.Type is BoolType) { @@ -2692,14 +2944,12 @@ namespace Microsoft.Dafny { CHECK_NEXT_CONJUNCT: ; } // we have checked every conjunct in the range expression and still have not discovered good bounds - if (errorMessage != null) { - Error(tok, "{0}, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{1}'", errorMessage, bv.Name); - } - return null; + missingBounds.Add(bv); // record failing bound variable + foundError = true; } 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) } - return bounds; + return foundError ? null : bounds; } /// @@ -2996,8 +3246,9 @@ namespace Microsoft.Dafny { } } - void ResolveReceiver(Expression expr, bool twoState, bool specContext) + void ResolveReceiver(Expression expr, bool twoState, bool allowGhostFeatures) { + Contract.Requires(allowGhostFeatures); Contract.Requires(expr != null); Contract.Requires(currentClass != null); Contract.Ensures(expr.Type != null); @@ -3007,14 +3258,20 @@ namespace Microsoft.Dafny { // making sure 'this' does not really get used when it's not available. expr.Type = GetThisType(expr.tok, currentClass); } else { - ResolveExpression(expr, twoState, specContext); + ResolveExpression(expr, twoState, allowGhostFeatures); } } - void ResolveSeqSelectExpr(SeqSelectExpr e, bool twoState, bool specContext, bool allowNonUnitArraySelection) { + void ResolveSeqSelectExpr(SeqSelectExpr e, bool twoState, bool allowGhostFeatures, bool allowNonUnitArraySelection) { + Contract.Requires(allowGhostFeatures); Contract.Requires(e != null); + if (e.Type != null) { + // already resolved + return; + } + bool seqErr = false; - ResolveExpression(e.Seq, twoState, specContext); + ResolveExpression(e.Seq, twoState, allowGhostFeatures); Contract.Assert(e.Seq.Type != null); // follows from postcondition of ResolveExpression Type elementType = new InferredTypeProxy(); Type expectedType; @@ -3028,14 +3285,14 @@ namespace Microsoft.Dafny { seqErr = true; } if (e.E0 != null) { - ResolveExpression(e.E0, twoState, specContext); + ResolveExpression(e.E0, twoState, allowGhostFeatures); Contract.Assert(e.E0.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E0.Type, Type.Int)) { Error(e.E0, "sequence/array selection requires integer indices (got {0})", e.E0.Type); } } if (e.E1 != null) { - ResolveExpression(e.E1, twoState, specContext); + ResolveExpression(e.E1, twoState, allowGhostFeatures); Contract.Assert(e.E1.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E1.Type, Type.Int)) { Error(e.E1, "sequence/array selection requires integer indices (got {0})", e.E1.Type); diff --git a/Dafny/Scanner.cs b/Dafny/Scanner.cs index 940c249f..393d0c0c 100644 --- a/Dafny/Scanner.cs +++ b/Dafny/Scanner.cs @@ -211,8 +211,8 @@ public class UTF8Buffer: Buffer { public class Scanner { const char EOL = '\n'; const int eofSym = 0; /* pdt */ - const int maxT = 106; - const int noSym = 106; + const int maxT = 107; + const int noSym = 107; [ContractInvariantMethod] @@ -515,33 +515,34 @@ public class Scanner { case "reads": t.kind = 41; break; case "match": t.kind = 44; break; case "case": t.kind = 45; break; - case "label": t.kind = 47; break; - case "break": t.kind = 48; break; - case "return": t.kind = 49; break; - case "new": t.kind = 51; break; - case "choose": t.kind = 55; break; - case "havoc": t.kind = 56; break; - case "if": t.kind = 57; break; - case "else": t.kind = 58; break; - case "while": t.kind = 59; break; - case "invariant": t.kind = 60; break; - case "call": t.kind = 61; break; - case "foreach": t.kind = 62; break; - case "in": t.kind = 63; break; - case "assert": t.kind = 64; break; - case "assume": t.kind = 65; break; - case "use": t.kind = 66; break; - case "print": t.kind = 67; break; - case "false": t.kind = 91; break; - case "true": t.kind = 92; break; - case "null": t.kind = 93; break; - case "this": t.kind = 94; break; - case "fresh": t.kind = 95; break; - case "allocated": t.kind = 96; break; - case "old": t.kind = 97; break; - case "then": t.kind = 98; break; - case "forall": t.kind = 100; break; - case "exists": t.kind = 102; break; + case "call": t.kind = 47; break; + case "label": t.kind = 48; break; + case "break": t.kind = 49; break; + case "return": t.kind = 50; break; + case "new": t.kind = 52; break; + case "choose": t.kind = 56; break; + case "havoc": t.kind = 57; break; + case "if": t.kind = 58; break; + case "else": t.kind = 59; break; + case "while": t.kind = 60; break; + case "invariant": t.kind = 61; break; + case "callXYZXYZ": t.kind = 62; break; + case "foreach": t.kind = 63; break; + case "in": t.kind = 64; break; + case "assert": t.kind = 65; break; + case "assume": t.kind = 66; break; + case "use": t.kind = 67; break; + case "print": t.kind = 68; break; + case "false": t.kind = 92; break; + case "true": t.kind = 93; break; + case "null": t.kind = 94; break; + case "this": t.kind = 95; break; + case "fresh": t.kind = 96; break; + case "allocated": t.kind = 97; break; + case "old": t.kind = 98; break; + case "then": t.kind = 99; break; + case "forall": t.kind = 101; break; + case "exists": t.kind = 103; break; default: break; } } @@ -661,70 +662,70 @@ public class Scanner { case 25: {t.kind = 46; break;} case 26: - {t.kind = 50; break;} + {t.kind = 51; break;} case 27: - {t.kind = 52; break;} - case 28: {t.kind = 53; break;} + case 28: + {t.kind = 54; break;} case 29: if (ch == '>') {AddCh(); goto case 30;} else {goto case 0;} case 30: - {t.kind = 68; break;} - case 31: {t.kind = 69; break;} - case 32: + case 31: {t.kind = 70; break;} - case 33: + case 32: {t.kind = 71; break;} + case 33: + {t.kind = 72; break;} case 34: if (ch == '&') {AddCh(); goto case 35;} else {goto case 0;} case 35: - {t.kind = 72; break;} - case 36: {t.kind = 73; break;} - case 37: + case 36: {t.kind = 74; break;} - case 38: + case 37: {t.kind = 75; break;} + case 38: + {t.kind = 76; break;} case 39: - {t.kind = 78; break;} - case 40: {t.kind = 79; break;} - case 41: + case 40: {t.kind = 80; break;} + case 41: + {t.kind = 81; break;} case 42: if (ch == 'n') {AddCh(); goto case 43;} else {goto case 0;} case 43: - {t.kind = 81; break;} - case 44: {t.kind = 82; break;} - case 45: + case 44: {t.kind = 83; break;} - case 46: + case 45: {t.kind = 84; break;} - case 47: + case 46: {t.kind = 85; break;} - case 48: + case 47: {t.kind = 86; break;} - case 49: + case 48: {t.kind = 87; break;} - case 50: + case 49: {t.kind = 88; break;} + case 50: + {t.kind = 89; break;} case 51: - {t.kind = 90; break;} + {t.kind = 91; break;} case 52: - {t.kind = 99; break;} + {t.kind = 100; break;} case 53: - {t.kind = 101; break;} + {t.kind = 102; break;} case 54: - {t.kind = 103; break;} - case 55: {t.kind = 104; break;} - case 56: + case 55: {t.kind = 105; break;} + case 56: + {t.kind = 106; break;} case 57: recEnd = pos; recKind = 16; if (ch == '>') {AddCh(); goto case 25;} @@ -748,23 +749,23 @@ public class Scanner { if (ch == '=') {AddCh(); goto case 39;} else {t.kind = 24; break;} case 62: - recEnd = pos; recKind = 54; + recEnd = pos; recKind = 55; if (ch == '.') {AddCh(); goto case 52;} - else {t.kind = 54; break;} + else {t.kind = 55; break;} case 63: - recEnd = pos; recKind = 89; + recEnd = pos; recKind = 90; if (ch == '=') {AddCh(); goto case 40;} else if (ch == '!') {AddCh(); goto case 41;} else if (ch == 'i') {AddCh(); goto case 42;} - else {t.kind = 89; break;} + else {t.kind = 90; break;} case 64: - recEnd = pos; recKind = 76; + recEnd = pos; recKind = 77; if (ch == '>') {AddCh(); goto case 32;} - else {t.kind = 76; break;} + else {t.kind = 77; break;} case 65: - recEnd = pos; recKind = 77; + recEnd = pos; recKind = 78; if (ch == '=') {AddCh(); goto case 29;} - else {t.kind = 77; break;} + else {t.kind = 78; break;} } t.val = new String(tval, 0, tlen); diff --git a/Dafny/Translator.cs b/Dafny/Translator.cs index 0c750d8b..4fb42099 100644 --- a/Dafny/Translator.cs +++ b/Dafny/Translator.cs @@ -3232,6 +3232,13 @@ namespace Microsoft.Dafny { Contract.Assert(ifCmd != null); // follows from the fact that s.Cases.Count + s.MissingCases.Count != 0. builder.Add(ifCmd); + } else if (stmt is ConcreteSyntaxStatement) { + var s = (ConcreteSyntaxStatement)stmt; + // TODO: Update statements should perform multiple assignments in parallel! + foreach (var ss in s.ResolvedStatements) { + TrStmt(ss, builder, locals, etran); + } + } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement } @@ -3905,12 +3912,14 @@ namespace Microsoft.Dafny { { Contract.Requires(tok != null); Contract.Requires(lhs != null); + // TODO: Contract.Requires(!(lhs is ConcreteSyntaxExpression)); Contract.Requires(rhs != null); Contract.Requires(builder != null); Contract.Requires(cce.NonNullElements(locals)); Contract.Requires(etran != null); Contract.Requires(predef != null); + lhs = lhs.Resolved; // TODO: delete this line and instead bring in the commented-out precondition above TrStmt_CheckWellformed(lhs, builder, locals, etran, true); if (lhs is IdentifierExpr) { -- cgit v1.2.3