From 701741248e5831c1976b8cb2a2cc412987a1332e Mon Sep 17 00:00:00 2001 From: Michael Lowell Roberts Date: Mon, 20 Jul 2015 14:06:06 -0700 Subject: clarified error message that occurs when the "opened" keyword is left off of a module import. --- Test/dafny0/ResolutionErrors.dfy.expect | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index c215d354..ae3e8cbf 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -58,8 +58,8 @@ ResolutionErrors.dfy(987,11): Error: Wrong number of type arguments (2 instead o ResolutionErrors.dfy(988,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C ResolutionErrors.dfy(999,7): Error: Duplicate name of top-level declaration: BadSyn2 ResolutionErrors.dfy(996,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List -ResolutionErrors.dfy(997,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name?) -ResolutionErrors.dfy(998,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name?) +ResolutionErrors.dfy(997,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(998,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') ResolutionErrors.dfy(1005,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A ResolutionErrors.dfy(1008,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A ResolutionErrors.dfy(1012,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A @@ -68,7 +68,7 @@ ResolutionErrors.dfy(1024,7): Error: Cycle among redirecting types (newtypes, ty ResolutionErrors.dfy(1029,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A ResolutionErrors.dfy(1048,21): Error: unresolved identifier: x ResolutionErrors.dfy(1055,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P -ResolutionErrors.dfy(1067,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name?) +ResolutionErrors.dfy(1067,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') ResolutionErrors.dfy(1077,6): Error: RHS (of type P) not assignable to LHS (of type P) ResolutionErrors.dfy(1082,6): Error: RHS (of type P) not assignable to LHS (of type P) ResolutionErrors.dfy(1087,6): Error: RHS (of type P) not assignable to LHS (of type P) @@ -82,8 +82,8 @@ ResolutionErrors.dfy(1225,26): Error: the type of this variable is underspecifie ResolutionErrors.dfy(1226,31): Error: the type of this variable is underspecified ResolutionErrors.dfy(1227,29): Error: the type of this variable is underspecified ResolutionErrors.dfy(1237,34): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1253,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name?) -ResolutionErrors.dfy(1254,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name?) +ResolutionErrors.dfy(1253,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1254,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') ResolutionErrors.dfy(1291,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) ResolutionErrors.dfy(1301,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) ResolutionErrors.dfy(1329,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) -- cgit v1.2.3 From 7e7eb1a4177e03f6bb22411b7246db1d26f5ed27 Mon Sep 17 00:00:00 2001 From: Rustan Leino Date: Wed, 29 Jul 2015 17:35:18 -0700 Subject: Fixed crash in resolution where, after reporting an error, the cases #type and #module were not handled --- Source/Dafny/Resolver.cs | 4 ++++ Test/dafny0/ResolutionErrors.dfy | 24 ++++++++++++++++++++++++ Test/dafny0/ResolutionErrors.dfy.expect | 16 +++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index e3083133..e977dbd5 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -4491,6 +4491,10 @@ namespace Microsoft.Dafny // something is wrong; either aa or bb wasn't properly resolved, or they don't unify return false; } + } else if (a is Resolver_IdentifierExpr.ResolverType_Type) { + return b is Resolver_IdentifierExpr.ResolverType_Type; + } else if (a is Resolver_IdentifierExpr.ResolverType_Module) { + return b is Resolver_IdentifierExpr.ResolverType_Module; } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 8c910959..900c7459 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -1349,3 +1349,27 @@ module TupleEqualitySupport { datatype GoodRecord = GoodRecord(set<(int,int)>) datatype BadRecord = BadRecord(set<(int, int->bool)>) // error: this tuple type does not support equality } + +// ------------------- non-type variable names ------------------- + +module NonTypeVariableNames { + type X = int + + module Y { } + + method M(m: map) + { + assert X == X; // error (x2): type name used as variable + assert Y == Y; // error (x2): module name used as variable + assert X in m; // error (x2): type name used as variable + assert Y in m; // error (x2): module name used as variable + } + + method N(k: int) + { + assert k == X; // error (x2): type name used as variable + assert k == Y; // error (x2): module name used as variable + X := k; // error: type name used as variable + Y := k; // error: module name used as variable + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index ae3e8cbf..481b47e0 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -90,6 +90,20 @@ ResolutionErrors.dfy(1329,15): Error: The name Inner ambiguously refers to a typ ResolutionErrors.dfy(1339,29): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(1341,49): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(1341,54): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1362,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1362,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1363,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1363,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1364,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1364,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) +ResolutionErrors.dfy(1365,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1365,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) +ResolutionErrors.dfy(1370,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1370,13): Error: arguments must have the same type (got int and #type) +ResolutionErrors.dfy(1371,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1371,13): Error: arguments must have the same type (got int and #module) +ResolutionErrors.dfy(1372,4): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1373,4): Error: name of module (Y) is used as a variable ResolutionErrors.dfy(432,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -182,4 +196,4 @@ ResolutionErrors.dfy(1106,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1127,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1134,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1149,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -184 resolution/type errors detected in ResolutionErrors.dfy +198 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From d023b0e19f7bf886801a3a059511b8449d8ab223 Mon Sep 17 00:00:00 2001 From: Rustan Leino Date: Fri, 31 Jul 2015 16:58:36 -0700 Subject: Bug fix: check that assign-such-that constraint is of type boolean --- Source/Dafny/Resolver.cs | 3 +++ Test/dafny0/ResolutionErrors.dfy | 15 +++++++++++++++ Test/dafny0/ResolutionErrors.dfy.expect | 6 +++++- 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index e977dbd5..a58d6e6c 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -6100,6 +6100,9 @@ namespace Microsoft.Dafny s.IsGhost = s.Lhss.TrueForAll(AssignStmt.LhsIsToGhost); var ec = ErrorCount; ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, specContextOnly)); + if (!UnifyTypes(s.Expr.Type, Type.Bool)) { + Error(s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type); + } if (ec == ErrorCount && !s.IsGhost && s.AssumeToken == null && !specContextOnly) { CheckIsNonGhost(s.Expr); diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 900c7459..1354e533 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -1373,3 +1373,18 @@ module NonTypeVariableNames { Y := k; // error: module name used as variable } } + +// ------------------- assign-such-that and let-such-that ------------------- + +module SuchThat { + method M() { + var x: int; + x :| 5 + 7; // error: constraint should be boolean + x :| x; // error: constraint should be boolean + var y :| 4; // error: constraint should be boolean + } + function F(): int { + var w :| 6 + 8; // error: constraint should be boolean + w + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index 481b47e0..b5c93ac1 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -104,6 +104,10 @@ ResolutionErrors.dfy(1371,16): Error: name of module (Y) is used as a variable ResolutionErrors.dfy(1371,13): Error: arguments must have the same type (got int and #module) ResolutionErrors.dfy(1372,4): Error: name of type (X) is used as a variable ResolutionErrors.dfy(1373,4): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1382,11): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1383,9): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1384,13): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1387,15): Error: type of RHS of let-such-that expression must be boolean (got int) ResolutionErrors.dfy(432,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -196,4 +200,4 @@ ResolutionErrors.dfy(1106,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1127,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1134,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1149,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -198 resolution/type errors detected in ResolutionErrors.dfy +202 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 800885b4d7d0164803c0c2f117b78c65479283f9 Mon Sep 17 00:00:00 2001 From: leino Date: Sun, 20 Sep 2015 21:51:42 -0700 Subject: Preliminary refactoring of ghost-statement computations to after type checking --- Source/Dafny/DafnyAst.cs | 84 +++-- Source/Dafny/Resolver.cs | 478 +++++++++++++++++++++++---- Test/dafny0/AssumptionVariables0.dfy | 8 +- Test/dafny0/AssumptionVariables0.dfy.expect | 5 +- Test/dafny0/ParallelResolveErrors.dfy | 4 +- Test/dafny0/ParallelResolveErrors.dfy.expect | 5 +- Test/dafny0/ResolutionErrors.dfy | 16 +- Test/dafny0/ResolutionErrors.dfy.expect | 13 +- Test/dafny0/TypeTests.dfy.expect | 2 +- 9 files changed, 495 insertions(+), 120 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs index 9bff2038..83db732e 100644 --- a/Source/Dafny/DafnyAst.cs +++ b/Source/Dafny/DafnyAst.cs @@ -1655,7 +1655,7 @@ namespace Microsoft.Dafny { // it is abstract). Otherwise, it points to that definition. public ModuleSignature CompileSignature = null; // This is the version of the signature that should be used at compile time. public ModuleSignature Refines = null; - public bool IsGhost = false; + public bool IsAbstract = false; public ModuleSignature() {} public bool FindSubmodule(string name, out ModuleSignature pp) { @@ -3461,7 +3461,23 @@ namespace Microsoft.Dafny { Contract.Invariant(EndTok != null); } +#if OLD_GHOST_HANDLING public bool IsGhost; // filled in by resolution +#else + public static bool ReadyToDealWithGhostField = true; + private bool izzaGhost; + public bool IsGhost { + get { + Contract.Requires(ReadyToDealWithGhostField); + return izzaGhost; + } + set { + Contract.Requires(ReadyToDealWithGhostField); + izzaGhost = value; + } + } + public bool C_IsGhost; // new ghost computation +#endif public Statement(IToken tok, IToken endTok, Attributes attrs) { Contract.Requires(tok != null); @@ -4051,18 +4067,42 @@ namespace Microsoft.Dafny { /// This method assumes "lhs" has been successfully resolved. /// public static bool LhsIsToGhost(Expression lhs) { + Contract.Requires(lhs != null); + return LhsIsToGhost_Which(lhs) == NonGhostKind.IsGhost; + } + public enum NonGhostKind { IsGhost, Variable, Field, ArrayElement } + public static string NonGhostKind_To_String(NonGhostKind gk) { + Contract.Requires(gk != NonGhostKind.IsGhost); + switch (gk) { + case NonGhostKind.Variable: return "non-ghost variable"; + case NonGhostKind.Field: return "non-ghost field"; + case NonGhostKind.ArrayElement: return "array element"; + default: + Contract.Assume(false); // unexpected NonGhostKind + throw new cce.UnreachableException(); // please compiler + } + } + /// + /// This method assumes "lhs" has been successfully resolved. + /// + public static NonGhostKind LhsIsToGhost_Which(Expression lhs) { Contract.Requires(lhs != null); lhs = lhs.Resolved; if (lhs is IdentifierExpr) { var x = (IdentifierExpr)lhs; - return x.Var.IsGhost; + if (!x.Var.IsGhost) { + return NonGhostKind.Variable; + } } else if (lhs is MemberSelectExpr) { var x = (MemberSelectExpr)lhs; - return x.Member.IsGhost; + if (!x.Member.IsGhost) { + return NonGhostKind.Field; + } } else { // LHS denotes an array element, which is always non-ghost - return false; + return NonGhostKind.ArrayElement; } + return NonGhostKind.IsGhost; } } @@ -7741,24 +7781,6 @@ namespace Microsoft.Dafny { public class BottomUpVisitor { - public void Visit(Expression expr) { - Contract.Requires(expr != null); - // recursively visit all subexpressions and all substatements - expr.SubExpressions.Iter(Visit); - if (expr is StmtExpr) { - // a StmtExpr also has a sub-statement - var e = (StmtExpr)expr; - Visit(e.S); - } - VisitOneExpr(expr); - } - public void Visit(Statement stmt) { - Contract.Requires(stmt != null); - // recursively visit all subexpressions and all substatements - stmt.SubExpressions.Iter(Visit); - stmt.SubStatements.Iter(Visit); - VisitOneStmt(stmt); - } public void Visit(IEnumerable exprs) { exprs.Iter(Visit); } @@ -7801,6 +7823,24 @@ namespace Microsoft.Dafny { if (function.Body != null) { Visit(function.Body); } //TODO More? } + public void Visit(Expression expr) { + Contract.Requires(expr != null); + // recursively visit all subexpressions and all substatements + expr.SubExpressions.Iter(Visit); + if (expr is StmtExpr) { + // a StmtExpr also has a sub-statement + var e = (StmtExpr)expr; + Visit(e.S); + } + VisitOneExpr(expr); + } + public void Visit(Statement stmt) { + Contract.Requires(stmt != null); + // recursively visit all subexpressions and all substatements + stmt.SubExpressions.Iter(Visit); + stmt.SubStatements.Iter(Visit); + VisitOneStmt(stmt); + } protected virtual void VisitOneExpr(Expression expr) { Contract.Requires(expr != null); // by default, do nothing diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index 66f8f449..57a42c73 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -345,7 +345,7 @@ namespace Microsoft.Dafny "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of " + Util.Comma(".", abs.Path, x => x.val)); } - abs.Signature.IsGhost = compileSig.IsGhost; + abs.Signature.IsAbstract = compileSig.IsAbstract; // always keep the ghost information, to supress a spurious error message when the compile module isn't actually a refinement } } @@ -835,14 +835,14 @@ namespace Microsoft.Dafny foreach (var kv in m.StaticMembers) { info.StaticMembers[kv.Key] = kv.Value; } - info.IsGhost = m.IsGhost; + info.IsAbstract = m.IsAbstract; return info; } ModuleSignature RegisterTopLevelDecls(ModuleDefinition moduleDef, bool useImports) { Contract.Requires(moduleDef != null); var sig = new ModuleSignature(); sig.ModuleDef = moduleDef; - sig.IsGhost = moduleDef.IsAbstract; + sig.IsAbstract = moduleDef.IsAbstract; List declarations = moduleDef.TopLevelDecls; // First go through and add anything from the opened imports @@ -1195,7 +1195,7 @@ namespace Microsoft.Dafny var sig = RegisterTopLevelDecls(mod, false); sig.Refines = p.Refines; sig.CompileSignature = p; - sig.IsGhost = p.IsGhost; + sig.IsAbstract = p.IsAbstract; sig.ExclusiveRefinement = p.ExclusiveRefinement; mods.Add(mod); ResolveModuleDefinition(mod, sig); @@ -1279,7 +1279,7 @@ namespace Microsoft.Dafny } else if (d is ModuleDecl) { var decl = (ModuleDecl)d; if (!def.IsAbstract) { - if (decl.Signature.IsGhost) + if (decl.Signature.IsAbstract) { if (!(def.IsDefaultModule)) // _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to // trusted verification, as toplevels can't be trusted if they invoke abstract module members. @@ -1400,43 +1400,7 @@ namespace Microsoft.Dafny ResolveClassMemberBodies(cl); } allTypeParameters.PopMarker(); - SolveAllTypeConstraints(); - } - - if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - foreach (var e in needFiniteBoundsChecks_SetComprehension) { - CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.Range, true, true, out missingBounds); - if (missingBounds.Count != 0) { - e.MissingBounds = missingBounds; - if (e.Finite) { - foreach (var bv in e.MissingBounds) { - reporter.Error(MessageSource.Resolver, e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - } - } - } - foreach (var e in needFiniteBoundsChecks_LetSuchThatExpr) { - Contract.Assert(!e.Exact); // only let-such-that expressions are ever added to the list - Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully - var constraint = e.RHSs[0]; - CheckTypeInference(constraint); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - var vars = new List(e.BoundVars); - var bestBounds = DiscoverBestBounds_MultipleVars(vars, constraint, true, false, out missingBounds); - if (missingBounds.Count != 0) { - e.Constraint_MissingBounds = missingBounds; - foreach (var bv in e.Constraint_MissingBounds) { - reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - } else { - e.Constraint_Bounds = bestBounds; - } - } } - needFiniteBoundsChecks_SetComprehension.Clear(); - needFiniteBoundsChecks_LetSuchThatExpr.Clear(); Dictionary nativeTypeMap = new Dictionary(); foreach (var nativeType in NativeTypes) { @@ -1546,6 +1510,42 @@ namespace Microsoft.Dafny } } + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + // At this point, it is necessary to know for each statement and expression if it is ghost or not + foreach (var e in needFiniteBoundsChecks_SetComprehension) { + CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds + List missingBounds; + e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.Range, true, true, out missingBounds); + if (missingBounds.Count != 0) { + e.MissingBounds = missingBounds; + if (e.Finite) { + foreach (var bv in e.MissingBounds) { + reporter.Error(MessageSource.Resolver, e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + } + } + } + } + foreach (var e in needFiniteBoundsChecks_LetSuchThatExpr) { + Contract.Assert(!e.Exact); // only let-such-that expressions are ever added to the list + Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully + var constraint = e.RHSs[0]; + CheckTypeInference(constraint); // we need to resolve operators before the call to DiscoverBounds + List missingBounds; + var vars = new List(e.BoundVars); + var bestBounds = DiscoverBestBounds_MultipleVars(vars, constraint, true, false, out missingBounds); + if (missingBounds.Count != 0) { + e.Constraint_MissingBounds = missingBounds; + foreach (var bv in e.Constraint_MissingBounds) { + reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + } + } else { + e.Constraint_Bounds = bestBounds; + } + } + } + needFiniteBoundsChecks_SetComprehension.Clear(); + needFiniteBoundsChecks_LetSuchThatExpr.Clear(); + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // fill in the postconditions and bodies of prefix lemmas foreach (var com in ModuleDefinition.AllFixpointLemmas(declarations)) { @@ -2972,6 +2972,294 @@ namespace Microsoft.Dafny #endregion CheckEqualityTypes + // ------------------------------------------------------------------------------------------------------ + // ----- ComputeGhostInterest --------------------------------------------------------------------------- + // ------------------------------------------------------------------------------------------------------ + #region ComputeGhostInterest + public void ComputeGhostInterest(Statement stmt, ICodeContext codeContext) { + Contract.Requires(stmt != null); + Contract.Requires(codeContext != null); + var visitor = new GhostInterest_Visitor(codeContext, this); + visitor.Visit(stmt, codeContext.IsGhost); + } + class GhostInterest_Visitor + { + readonly ICodeContext codeContext; + readonly Resolver resolver; + public GhostInterest_Visitor(ICodeContext codeContext, Resolver resolver) { + Contract.Requires(codeContext != null); + Contract.Requires(resolver != null); + this.codeContext = codeContext; + this.resolver = resolver; + } + protected void Error(Statement stmt, string msg, params object[] msgArgs) { + Contract.Requires(stmt != null); + Contract.Requires(msg != null); + Contract.Requires(msgArgs != null); + resolver.reporter.Error(MessageSource.Resolver, stmt, msg, msgArgs); + } + protected void Error(Expression expr, string msg, params object[] msgArgs) { + Contract.Requires(expr != null); + Contract.Requires(msg != null); + Contract.Requires(msgArgs != null); + resolver.reporter.Error(MessageSource.Resolver, expr, msg, msgArgs); + } + protected void Error(IToken tok, string msg, params object[] msgArgs) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Contract.Requires(msgArgs != null); + resolver.reporter.Error(MessageSource.Resolver, tok, msg, msgArgs); + } + /// + /// This method does three things: + /// 0. Reports an error if "mustBeErasable" and the statement assigns to a non-ghost field + /// 1. Reports an error if the statement assigns to a non-ghost field and the right-hand side + /// depends on a ghost. + /// 2. Sets to "true" the .IsGhost field of the statement if it should be erased during compilation. + /// In that case, substatements should be visited with "mustBeErasable". + /// Note that the method called by a StmtExpr must be ghost; however, this is checked elsewhere. For + /// this reason, it is not necessary to visit all subexpressions, unless the subexpression + /// matter for the ghost checking/recording of "stmt". + /// Note, it is important to set the statement's ghost status before descending into its sub-statements, + /// because break statements look at the ghost status of its enclosing statements. + /// + public void Visit(Statement stmt, bool mustBeErasable) { + Contract.Assume(!codeContext.IsGhost || mustBeErasable); // (this is really a precondition) codeContext.IsGhost ==> mustBeErasable + stmt.IsGhost = false; // DEBUG + + if (stmt is PredicateStmt) { + stmt.C_IsGhost = true; + + } else if (stmt is PrintStmt) { + var s = (PrintStmt)stmt; + if (mustBeErasable) { + Error(stmt, "print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); + } else { + s.Args.Iter(resolver.CheckIsNonGhost); + } + + } else if (stmt is BreakStmt) { + var s = (BreakStmt)stmt; + if (mustBeErasable) { + if (!s.TargetStmt.C_IsGhost && !resolver.inSpecOnlyContext[s.TargetStmt]) { // TODO: inSpecOnlyContext should probably move from Resolver to GhostInterest_Visitor + var targetIsLoop = s.TargetStmt is WhileStmt || s.TargetStmt is AlternativeLoopStmt; + Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure")); + } + } + + } else if (stmt is ProduceStmt) { + var s = (ProduceStmt)stmt; + var kind = stmt is YieldStmt ? "yield" : "return"; + if (mustBeErasable && !codeContext.IsGhost) { + Error(stmt, "{0} statement is not allowed in this context (because it is guarded by a specification-only expression)", kind); + } + if (s.hiddenUpdate != null) { + Visit(s.hiddenUpdate, mustBeErasable); + } + + } else if (stmt is AssignSuchThatStmt) { + var s = (AssignSuchThatStmt)stmt; + s.C_IsGhost = mustBeErasable || s.AssumeToken != null || s.Lhss.Any(AssignStmt.LhsIsToGhost); + if (mustBeErasable && !codeContext.IsGhost) { + foreach (var lhs in s.Lhss) { + var gk = AssignStmt.LhsIsToGhost_Which(lhs); + if (gk != AssignStmt.NonGhostKind.IsGhost) { + Error(lhs, "cannot assign to {0} in a ghost context", AssignStmt.NonGhostKind_To_String(gk)); + } + } + } else if (!mustBeErasable && s.AssumeToken == null && resolver.UsesSpecFeatures(s.Expr)) { + foreach (var lhs in s.Lhss) { + var gk = AssignStmt.LhsIsToGhost_Which(lhs); + if (gk != AssignStmt.NonGhostKind.IsGhost) { + Error(lhs, "{0} cannot be assigned a value that depends on a ghost", AssignStmt.NonGhostKind_To_String(gk)); + } + } + } + + } else if (stmt is UpdateStmt) { + var s = (UpdateStmt)stmt; + s.ResolvedStatements.Iter(ss => Visit(ss, mustBeErasable)); + s.C_IsGhost = s.ResolvedStatements.All(ss => ss.C_IsGhost); + + } else if (stmt is VarDeclStmt) { + var s = (VarDeclStmt)stmt; + if (mustBeErasable) { + foreach (var local in s.Locals) { + // a local variable in a specification-only context might as well be ghost + local.IsGhost = true; + } + } + foreach (var local in s.Locals) { + if (Attributes.Contains(local.Attributes, "assumption")) { + if (!local.IsGhost) { + Error(local.Tok, "assumption variable must be ghost"); + } + } + } + s.C_IsGhost = (s.Update == null || s.Update.C_IsGhost) && s.Locals.All(v => v.IsGhost); + if (s.Update != null) { + Visit(s.Update, mustBeErasable); + } + + } else if (stmt is AssignStmt) { + var s = (AssignStmt)stmt; + var lhs = s.Lhs.Resolved; + var gk = AssignStmt.LhsIsToGhost_Which(lhs); + if (gk == AssignStmt.NonGhostKind.IsGhost) { + s.C_IsGhost = true; + } else if (gk == AssignStmt.NonGhostKind.Variable && codeContext.IsGhost) { + // cool + } else if (mustBeErasable) { + Error(stmt, "Assignment to {0} is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)", + AssignStmt.NonGhostKind_To_String(gk)); + } else if (s.Rhs is ExprRhs) { + var rhs = (ExprRhs)s.Rhs; + resolver.CheckIsNonGhost(rhs.Expr); + } else if (s.Rhs is HavocRhs) { + // cool + } else { + var rhs = (TypeRhs)s.Rhs; + if (rhs.ArrayDimensions != null) { + foreach (var dim in rhs.ArrayDimensions) { + resolver.CheckIsNonGhost(dim); + } + } + if (rhs.InitCall != null) { + foreach (var arg in rhs.InitCall.Args) { + resolver.CheckIsNonGhost(arg); + } + } + } + + } else if (stmt is CallStmt) { + var s = (CallStmt)stmt; + var callee = s.Method; + Contract.Assert(callee != null); // follows from the invariant of CallStmt + s.C_IsGhost = callee.IsGhost; + // check in-parameters + if (mustBeErasable) { + if (!s.C_IsGhost) { + Error(s, "only ghost methods can be called from this context"); + } + } else { + resolver.CheckIsNonGhost(s.Receiver); + int j; + if (!callee.IsGhost) { + j = 0; + foreach (var e in s.Args) { + Contract.Assume(j < callee.Ins.Count); // this should have already been checked by the resolver + if (!callee.Ins[j].IsGhost) { + resolver.CheckIsNonGhost(e); + } + j++; + } + } + j = 0; + foreach (var e in s.Lhs) { + var resolvedLhs = e.Resolved; + if (callee.IsGhost || callee.Outs[j].IsGhost) { + // LHS must denote a ghost + if (resolvedLhs is IdentifierExpr) { + var ll = (IdentifierExpr)resolvedLhs; + if (!ll.Var.IsGhost) { + if (ll is AutoGhostIdentifierExpr && ll.Var is LocalVariable) { + // the variable was actually declared in this statement, so auto-declare it as ghost + ((LocalVariable)ll.Var).MakeGhost(); + } else { + Error(s, "actual out-parameter {0} is required to be a ghost variable", j); + } + } + } else if (resolvedLhs is MemberSelectExpr) { + var ll = (MemberSelectExpr)resolvedLhs; + if (!ll.Member.IsGhost) { + Error(s, "actual out-parameter {0} is required to be a ghost field", j); + } + } else { + // this is an array update, and arrays are always non-ghost + Error(s, "actual out-parameter {0} is required to be a ghost variable", j); + } + } + j++; + } + } + + } else if (stmt is BlockStmt) { + var s = (BlockStmt)stmt; + s.Body.Iter(ss => Visit(ss, mustBeErasable)); + s.C_IsGhost = s.Body.All(ss => ss.C_IsGhost); // mark the block statement as ghost if all its substatements are ghost + + } else if (stmt is IfStmt) { + var s = (IfStmt)stmt; + s.C_IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard)); + Visit(s.Thn, s.C_IsGhost); + if (s.Els != null) { + Visit(s.Els, s.C_IsGhost); + } + // if both branches were all ghost, then we can mark the enclosing statement as ghost as well + s.C_IsGhost = s.C_IsGhost || (s.Thn.C_IsGhost && (s.Els == null || s.Els.C_IsGhost)); + + } else if (stmt is AlternativeStmt) { + var s = (AlternativeStmt)stmt; + s.C_IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard)); + s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.C_IsGhost))); + s.C_IsGhost = s.C_IsGhost || s.Alternatives.All(alt => alt.Body.All(ss => ss.C_IsGhost)); + + } else if (stmt is WhileStmt) { + var s = (WhileStmt)stmt; + s.C_IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard)); + if (s.Body != null) { + Visit(s.Body, s.C_IsGhost); + } + s.C_IsGhost = s.C_IsGhost || s.Body == null || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Body.C_IsGhost); + + } else if (stmt is AlternativeLoopStmt) { + var s = (AlternativeLoopStmt)stmt; + s.C_IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard)); + s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.C_IsGhost))); + s.C_IsGhost = s.C_IsGhost || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Alternatives.All(alt => alt.Body.All(ss => ss.C_IsGhost))); + + } else if (stmt is ForallStmt) { + var s = (ForallStmt)stmt; + s.C_IsGhost = mustBeErasable || s.Kind != ForallStmt.ParBodyKind.Assign || resolver.UsesSpecFeatures(s.Range); + if (s.Body != null) { + Visit(s.Body, s.C_IsGhost); + } + s.C_IsGhost = s.C_IsGhost || s.Body == null || s.Body.C_IsGhost; + + } else if (stmt is ModifyStmt) { + var s = (ModifyStmt)stmt; + if (s.Body != null) { + Visit(s.Body, mustBeErasable); + } + s.C_IsGhost = mustBeErasable; + + } else if (stmt is CalcStmt) { + var s = (CalcStmt)stmt; + s.C_IsGhost = true; + foreach (var h in s.Hints) { + Visit(h, true); + } + + } else if (stmt is MatchStmt) { + var s = (MatchStmt)stmt; + var mbe = mustBeErasable || resolver.UsesSpecFeatures(s.Source); + s.Cases.Iter(kase => kase.Body.Iter(ss => Visit(ss, mbe))); + s.C_IsGhost = mbe || s.Cases.All(kase => kase.Body.All(ss => ss.C_IsGhost)); + + } else if (stmt is SkeletonStatement) { + var s = (SkeletonStatement)stmt; + if (s.S != null) { + Visit(s.S, mustBeErasable); + } + + } else { + Contract.Assert(false); throw new cce.UnreachableException(); + } + stmt.IsGhost = stmt.C_IsGhost; // DEBUG + } + } + #endregion + // ------------------------------------------------------------------------------------------------------ // ----- FillInDefaultLoopDecreases --------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------------ @@ -3601,22 +3889,14 @@ namespace Microsoft.Dafny // order does not matter much for resolution, so resolve them in reverse order foreach (var attr in attrs.AsEnumerable()) { if (attr.Args != null) { - ResolveAttributeArgs(attr.Args, opts, true); - } - } - } - - void ResolveAttributeArgs(List args, ResolveOpts opts, bool allowGhosts) { - Contract.Requires(args != null); - foreach (var arg in args) { - Contract.Assert(arg != null); - int prevErrors = reporter.Count(ErrorLevel.Error); - ResolveExpression(arg, opts); - if (!allowGhosts) { - CheckIsNonGhost(arg); - } - if (prevErrors == reporter.Count(ErrorLevel.Error)) { - CheckTypeInference(arg); + foreach (var arg in attr.Args) { + Contract.Assert(arg != null); + int prevErrors = reporter.Count(ErrorLevel.Error); + ResolveExpression(arg, opts); + if (prevErrors == reporter.Count(ErrorLevel.Error)) { + CheckTypeInference(arg); + } + } } } } @@ -3718,9 +3998,11 @@ namespace Microsoft.Dafny ResolveExpression(r, new ResolveOpts(f, false, true)); // any type is fine } + SolveAllTypeConstraints(); if (f.Body != null) { var prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(f.Body, new ResolveOpts(f, false)); + SolveAllTypeConstraints(); if (!f.IsGhost && prevErrorCount == reporter.Count(ErrorLevel.Error)) { CheckIsNonGhost(f.Body); } @@ -3852,6 +4134,7 @@ namespace Microsoft.Dafny Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Postcondition must be a boolean (got {0})", e.E.Type); } + SolveAllTypeConstraints(); // Resolve body if (m.Body != null) { @@ -3862,8 +4145,12 @@ namespace Microsoft.Dafny var k = com.PrefixLemma.Ins[0]; scope.Push(k.Name, k); // we expect no name conflict for _k } - var codeContext = m; - ResolveBlockStatement(m.Body, m.IsGhost, codeContext); + var prevErrorCount = reporter.Count(ErrorLevel.Error); + ResolveBlockStatement(m.Body, m.IsGhost, m); + SolveAllTypeConstraints(); + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + ComputeGhostInterest(m.Body, m); + } } // attributes are allowed to mention both in- and out-parameters (including the implicit _k, for colemmas) @@ -3982,6 +4269,9 @@ namespace Microsoft.Dafny // Resolve body if (iter.Body != null) { ResolveBlockStatement(iter.Body, false, iter); + if (reporter.Count(ErrorLevel.Error) == postSpecErrorCount) { + ComputeGhostInterest(iter.Body, iter); + } } currentClass = null; @@ -4834,11 +5124,15 @@ namespace Microsoft.Dafny ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type); } else if (stmt is PrintStmt) { - PrintStmt s = (PrintStmt)stmt; - ResolveAttributeArgs(s.Args, new ResolveOpts(codeContext, false, specContextOnly), false); + var s = (PrintStmt)stmt; + var opts = new ResolveOpts(codeContext, false, specContextOnly); + s.Args.Iter(e => ResolveExpression(e, opts)); +#if OLD_GHOST_HANDLING + ResolveAttributeArgs(s.Args, new ResolveOpts(codeContext, false, specContextOnly)); if (specContextOnly) { reporter.Error(MessageSource.Resolver, 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)"); } +#endif } else if (stmt is BreakStmt) { var s = (BreakStmt)stmt; @@ -4848,10 +5142,12 @@ namespace Microsoft.Dafny reporter.Error(MessageSource.Resolver, s, "break label is undefined or not in scope: {0}", s.TargetLabel); } else { s.TargetStmt = target; +#if OLD_GHOST_HANDLING bool targetIsLoop = target is WhileStmt || target is AlternativeLoopStmt; if (specContextOnly && !s.TargetStmt.IsGhost && !inSpecOnlyContext[s.TargetStmt]) { reporter.Error(MessageSource.Resolver, stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure")); } +#endif } } else { if (loopStack.Count < s.BreakCount) { @@ -4863,9 +5159,11 @@ namespace Microsoft.Dafny target.Labels = new LList) not assignable to LHS (of type List) -ResolutionErrors.dfy(507,7): Error: RHS (of type List) not assignable to LHS (of type List) -ResolutionErrors.dfy(521,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) -ResolutionErrors.dfy(533,24): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree -ResolutionErrors.dfy(561,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(561,23): Error: type variable 'T' in the function call to 'P' could not be determined -ResolutionErrors.dfy(568,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(568,23): Error: type variable 'T' in the function call to 'P' could not be determined -ResolutionErrors.dfy(581,13): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(582,9): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(589,14): Error: new allocation not supported in forall statements -ResolutionErrors.dfy(594,11): Error: the body of the enclosing forall statement is not allowed to update heap locations -ResolutionErrors.dfy(594,14): Error: new allocation not allowed in ghost context -ResolutionErrors.dfy(604,23): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(611,15): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(611,15): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(620,17): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(622,29): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(624,17): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(642,21): Error: the type of this variable is underspecified -ResolutionErrors.dfy(680,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(690,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(693,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(704,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(705,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(706,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(709,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(728,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(731,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(736,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(737,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(738,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(741,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(766,19): Error: calls to methods with side-effects are not allowed inside a statement expression -ResolutionErrors.dfy(767,20): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(768,20): Error: wrong number of method result arguments (got 0, expected 1) -ResolutionErrors.dfy(780,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(790,4): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(801,36): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(810,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(824,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(825,6): Error: RHS (of type int) not assignable to LHS (of type object) -ResolutionErrors.dfy(826,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(831,6): Error: RHS (of type G) not assignable to LHS (of type object) -ResolutionErrors.dfy(832,6): Error: RHS (of type Dt) not assignable to LHS (of type object) -ResolutionErrors.dfy(833,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) -ResolutionErrors.dfy(895,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(896,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(901,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(902,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(903,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(904,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(905,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(906,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(987,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 -ResolutionErrors.dfy(988,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C -ResolutionErrors.dfy(999,7): Error: Duplicate name of top-level declaration: BadSyn2 -ResolutionErrors.dfy(996,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List -ResolutionErrors.dfy(997,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(998,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1005,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A -ResolutionErrors.dfy(1008,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1012,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1021,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed -ResolutionErrors.dfy(1024,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1029,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1048,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1055,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P -ResolutionErrors.dfy(1067,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1077,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1082,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1087,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1088,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1093,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1094,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1095,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1118,38): Error: 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 'o' -ResolutionErrors.dfy(1120,24): Error: 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 'o' -ResolutionErrors.dfy(1225,26): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1226,31): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1227,29): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1237,34): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1253,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1254,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1291,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) -ResolutionErrors.dfy(1301,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1329,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) -ResolutionErrors.dfy(1339,29): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1341,49): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1341,54): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1362,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1362,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1363,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1363,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1364,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1364,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) -ResolutionErrors.dfy(1365,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1365,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) -ResolutionErrors.dfy(1370,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1370,13): Error: arguments must have the same type (got int and #type) -ResolutionErrors.dfy(1371,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1371,13): Error: arguments must have the same type (got int and #module) -ResolutionErrors.dfy(1372,4): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1373,4): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1382,11): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1383,9): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1384,13): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1387,15): Error: type of RHS of let-such-that expression must be boolean (got int) -ResolutionErrors.dfy(432,2): Error: More than one anonymous constructor +ResolutionErrors.dfy(558,7): Error: RHS (of type List) not assignable to LHS (of type List) +ResolutionErrors.dfy(563,7): Error: RHS (of type List) not assignable to LHS (of type List) +ResolutionErrors.dfy(577,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) +ResolutionErrors.dfy(589,24): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree +ResolutionErrors.dfy(619,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(619,23): Error: type variable 'T' in the function call to 'P' could not be determined +ResolutionErrors.dfy(626,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(626,23): Error: type variable 'T' in the function call to 'P' could not be determined +ResolutionErrors.dfy(639,13): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(640,9): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(647,14): Error: new allocation not supported in forall statements +ResolutionErrors.dfy(652,11): Error: the body of the enclosing forall statement is not allowed to update heap locations +ResolutionErrors.dfy(652,14): Error: new allocation not allowed in ghost context +ResolutionErrors.dfy(662,23): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(669,15): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(669,15): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(678,17): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(680,29): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(682,17): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(700,21): Error: the type of this variable is underspecified +ResolutionErrors.dfy(738,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(748,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(751,22): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(762,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(763,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(764,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(767,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(786,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(789,22): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(794,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(795,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(796,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(799,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(824,19): Error: calls to methods with side-effects are not allowed inside a statement expression +ResolutionErrors.dfy(825,20): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(826,20): Error: wrong number of method result arguments (got 0, expected 1) +ResolutionErrors.dfy(838,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(848,4): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(859,36): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(868,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(882,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(883,6): Error: RHS (of type int) not assignable to LHS (of type object) +ResolutionErrors.dfy(884,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(889,6): Error: RHS (of type G) not assignable to LHS (of type object) +ResolutionErrors.dfy(890,6): Error: RHS (of type Dt) not assignable to LHS (of type object) +ResolutionErrors.dfy(891,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) +ResolutionErrors.dfy(953,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(954,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(959,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(960,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(961,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(962,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(963,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(964,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(1045,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 +ResolutionErrors.dfy(1046,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C +ResolutionErrors.dfy(1057,7): Error: Duplicate name of top-level declaration: BadSyn2 +ResolutionErrors.dfy(1054,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List +ResolutionErrors.dfy(1055,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1056,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1063,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A +ResolutionErrors.dfy(1066,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1070,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1079,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed +ResolutionErrors.dfy(1082,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1087,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1106,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1113,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P +ResolutionErrors.dfy(1125,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1135,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1140,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1145,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1146,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1151,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1152,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1153,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1176,38): Error: 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 'o' +ResolutionErrors.dfy(1178,24): Error: 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 'o' +ResolutionErrors.dfy(1283,26): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1284,31): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1285,29): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1295,34): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1311,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1312,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1349,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) +ResolutionErrors.dfy(1359,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1387,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) +ResolutionErrors.dfy(1397,29): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1399,49): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1399,54): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1420,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1420,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1421,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1421,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1422,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1422,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) +ResolutionErrors.dfy(1423,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1423,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) +ResolutionErrors.dfy(1428,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1428,13): Error: arguments must have the same type (got int and #type) +ResolutionErrors.dfy(1429,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1429,13): Error: arguments must have the same type (got int and #module) +ResolutionErrors.dfy(1430,4): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1431,4): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1440,11): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1441,9): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1442,13): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1445,15): Error: type of RHS of let-such-that expression must be boolean (got int) +ResolutionErrors.dfy(488,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') ResolutionErrors.dfy(92,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') @@ -124,25 +124,25 @@ ResolutionErrors.dfy(141,21): Error: ghost variables are allowed only in specifi ResolutionErrors.dfy(142,35): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(151,10): Error: only ghost methods can be called from this context ResolutionErrors.dfy(157,16): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(233,12): Error: trying to break out of more loop levels than there are enclosing loops -ResolutionErrors.dfy(408,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(410,14): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(412,10): Error: a hint is not allowed to update a variable declared outside the hint -ResolutionErrors.dfy(438,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called -ResolutionErrors.dfy(443,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called -ResolutionErrors.dfy(444,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called -ResolutionErrors.dfy(446,9): Error: class Lamb does not have an anonymous constructor -ResolutionErrors.dfy(844,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) -ResolutionErrors.dfy(848,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(851,12): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(859,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(869,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(880,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1036,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1039,20): Error: unresolved identifier: x -ResolutionErrors.dfy(1042,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1044,19): Error: unresolved identifier: x -ResolutionErrors.dfy(1046,19): Error: unresolved identifier: x +ResolutionErrors.dfy(231,12): Error: trying to break out of more loop levels than there are enclosing loops +ResolutionErrors.dfy(464,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(466,14): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(468,10): Error: a hint is not allowed to update a variable declared outside the hint +ResolutionErrors.dfy(494,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called +ResolutionErrors.dfy(499,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called +ResolutionErrors.dfy(500,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called +ResolutionErrors.dfy(502,9): Error: class Lamb does not have an anonymous constructor +ResolutionErrors.dfy(902,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) +ResolutionErrors.dfy(906,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(909,12): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(917,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(927,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(938,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1094,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1097,20): Error: unresolved identifier: x +ResolutionErrors.dfy(1100,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1102,19): Error: unresolved identifier: x +ResolutionErrors.dfy(1104,19): Error: unresolved identifier: x ResolutionErrors.dfy(12,16): Error: 'decreases *' is not allowed on ghost loops ResolutionErrors.dfy(24,11): Error: array selection requires an array2 (got array3) ResolutionErrors.dfy(25,12): Error: sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got array3) @@ -156,39 +156,39 @@ ResolutionErrors.dfy(62,14): Error: accessing member 'M' requires an instance ex ResolutionErrors.dfy(63,7): Error: unresolved identifier: N ResolutionErrors.dfy(66,8): Error: non-function expression (of type int) is called with parameters ResolutionErrors.dfy(67,14): Error: member 'z' does not exist in type 'Global' -ResolutionErrors.dfy(260,4): Error: label shadows an enclosing label -ResolutionErrors.dfy(265,2): Error: duplicate label -ResolutionErrors.dfy(291,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(292,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(294,9): Error: a constructor is allowed to be called only when an object is being allocated -ResolutionErrors.dfy(308,16): Error: arguments must have the same type (got int and DTD_List) -ResolutionErrors.dfy(309,16): Error: arguments must have the same type (got DTD_List and int) -ResolutionErrors.dfy(310,25): Error: arguments must have the same type (got bool and int) -ResolutionErrors.dfy(322,15): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(347,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) -ResolutionErrors.dfy(359,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) -ResolutionErrors.dfy(367,6): Error: arguments to + must be of a numeric type or a collection type (instead got bool) -ResolutionErrors.dfy(372,6): Error: all lines in a calculation must have the same type (got int after bool) -ResolutionErrors.dfy(375,6): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(375,6): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(376,10): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(376,10): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(381,10): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(381,10): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(470,7): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(476,2): Error: non-ghost variable cannot be assigned a value that depends on a ghost -ResolutionErrors.dfy(549,18): Error: unresolved identifier: w -ResolutionErrors.dfy(656,11): Error: lemmas are not allowed to have modifies clauses -ResolutionErrors.dfy(918,9): Error: unresolved identifier: s -ResolutionErrors.dfy(929,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) -ResolutionErrors.dfy(930,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) -ResolutionErrors.dfy(936,16): Error: condition is expected to be of type bool, but is int -ResolutionErrors.dfy(937,16): Error: member 3 does not exist in datatype _tuple#3 -ResolutionErrors.dfy(937,26): Error: member x does not exist in datatype _tuple#2 -ResolutionErrors.dfy(960,15): Error: arguments to / must have the same type (got real and int) -ResolutionErrors.dfy(961,10): Error: second argument to % must be of type int (instead got real) -ResolutionErrors.dfy(1106,8): Error: new cannot be applied to a trait -ResolutionErrors.dfy(1127,13): Error: first argument to / must be of numeric type (instead got set) -ResolutionErrors.dfy(1134,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1149,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(311,4): Error: label shadows an enclosing label +ResolutionErrors.dfy(316,2): Error: duplicate label +ResolutionErrors.dfy(342,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(343,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(345,9): Error: a constructor is allowed to be called only when an object is being allocated +ResolutionErrors.dfy(359,16): Error: arguments must have the same type (got int and DTD_List) +ResolutionErrors.dfy(360,16): Error: arguments must have the same type (got DTD_List and int) +ResolutionErrors.dfy(361,25): Error: arguments must have the same type (got bool and int) +ResolutionErrors.dfy(375,15): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(400,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) +ResolutionErrors.dfy(412,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) +ResolutionErrors.dfy(420,6): Error: arguments to + must be of a numeric type or a collection type (instead got bool) +ResolutionErrors.dfy(425,6): Error: all lines in a calculation must have the same type (got int after bool) +ResolutionErrors.dfy(428,6): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(428,6): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(429,10): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(429,10): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(434,10): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(434,10): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(526,7): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(532,2): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(603,18): Error: unresolved identifier: w +ResolutionErrors.dfy(714,11): Error: lemmas are not allowed to have modifies clauses +ResolutionErrors.dfy(976,9): Error: unresolved identifier: s +ResolutionErrors.dfy(987,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) +ResolutionErrors.dfy(988,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) +ResolutionErrors.dfy(994,16): Error: condition is expected to be of type bool, but is int +ResolutionErrors.dfy(995,16): Error: member 3 does not exist in datatype _tuple#3 +ResolutionErrors.dfy(995,26): Error: member x does not exist in datatype _tuple#2 +ResolutionErrors.dfy(1018,15): Error: arguments to / must have the same type (got real and int) +ResolutionErrors.dfy(1019,10): Error: second argument to % must be of type int (instead got real) +ResolutionErrors.dfy(1164,8): Error: new cannot be applied to a trait +ResolutionErrors.dfy(1185,13): Error: first argument to / must be of numeric type (instead got set) +ResolutionErrors.dfy(1192,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1207,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating 193 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 029f016b365c844137399b2153bf59339d5612b7 Mon Sep 17 00:00:00 2001 From: leino Date: Sun, 20 Sep 2015 22:11:33 -0700 Subject: Added back in various ghost tests --- Test/dafny0/ResolutionErrors.dfy | 10 +++++----- Test/dafny0/ResolutionErrors.dfy.expect | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index d38d2506..2fab6bf3 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -238,7 +238,7 @@ class GhostTests { p := p + 1; } } -/***KRML method BreakMayNotBeFineHere_Ghost(ghost t: int) +method BreakMayNotBeFineHere_Ghost(ghost t: int) { var n := 0; ghost var k := 0; @@ -295,7 +295,7 @@ class GhostTests { n := n + 1; p := p + 1; } - }****/ + } } method DuplicateLabels(n: int) { @@ -364,7 +364,7 @@ method DatatypeDestructors(d: DTD_List) { } } method DatatypeDestructors_Ghost(d: DTD_List) { -//KRML var g1 := d.g; // error: cannot use ghost member in non-ghost code + var g1 := d.g; // error: cannot use ghost member in non-ghost code } // ------------------- print statements --------------------------------------- @@ -439,7 +439,7 @@ method TestCalc_Ghost(m: int, n: int, a: bool, b: bool) { calc { n + m; -//KRML { print n + m; } // error: non-ghost statements are not allowed in hints + { print n + m; } // error: non-ghost statements are not allowed in hints m + n; } } @@ -605,7 +605,7 @@ method LetSuchThat(ghost z: int, n: nat) } method LetSuchThat_Ghost(ghost z: int, n: nat) { -//KRML var x := var y :| y < z; y; // error: contraint depend on ghost (z) + var x := var y :| y < z; y; // error: contraint depend on ghost (z) } // ------------ quantified variables whose types are not inferred ---------- diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index 55d2e79c..0286778b 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -125,6 +125,10 @@ ResolutionErrors.dfy(142,35): Error: ghost variables are allowed only in specifi ResolutionErrors.dfy(151,10): Error: only ghost methods can be called from this context ResolutionErrors.dfy(157,16): Error: 'decreases *' is not allowed on ghost loops ResolutionErrors.dfy(231,12): Error: trying to break out of more loop levels than there are enclosing loops +ResolutionErrors.dfy(251,27): Error: ghost-context break statement is not allowed to break out of non-ghost structure +ResolutionErrors.dfy(274,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(288,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(293,8): Error: return statement is not allowed in this context (because it is guarded by a specification-only expression) ResolutionErrors.dfy(464,11): Error: calls to methods with side-effects are not allowed inside a hint ResolutionErrors.dfy(466,14): Error: a hint is not allowed to update heap locations ResolutionErrors.dfy(468,10): Error: a hint is not allowed to update a variable declared outside the hint @@ -164,6 +168,7 @@ ResolutionErrors.dfy(345,9): Error: a constructor is allowed to be called only w ResolutionErrors.dfy(359,16): Error: arguments must have the same type (got int and DTD_List) ResolutionErrors.dfy(360,16): Error: arguments must have the same type (got DTD_List and int) ResolutionErrors.dfy(361,25): Error: arguments must have the same type (got bool and int) +ResolutionErrors.dfy(367,14): Error: ghost fields are allowed only in specification contexts ResolutionErrors.dfy(375,15): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(400,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) ResolutionErrors.dfy(412,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) @@ -175,9 +180,11 @@ ResolutionErrors.dfy(429,10): Error: first argument to ==> must be of type bool ResolutionErrors.dfy(429,10): Error: second argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(434,10): Error: first argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(434,10): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(442,6): Error: 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) ResolutionErrors.dfy(526,7): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(532,2): Error: non-ghost variable cannot be assigned a value that depends on a ghost ResolutionErrors.dfy(603,18): Error: unresolved identifier: w +ResolutionErrors.dfy(608,24): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(714,11): Error: lemmas are not allowed to have modifies clauses ResolutionErrors.dfy(976,9): Error: unresolved identifier: s ResolutionErrors.dfy(987,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) @@ -191,4 +198,4 @@ ResolutionErrors.dfy(1164,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1185,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1192,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1207,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -193 resolution/type errors detected in ResolutionErrors.dfy +200 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 0c1ec594e68dab4fcd458a00f9f7a1ac6de2e218 Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 28 Sep 2015 13:16:15 -0700 Subject: Changed computation of ghosts until pass 2 of resolution. Other clean-up in resolution passes, like: Include everything of type "char" into bounds that are discovered, and likewise for reference types. Allow more set comprehensions, determining if they are finite based on their argument type. Changed CalcExpr.SubExpressions to not include computed expressions. --- Binaries/DafnyRuntime.cs | 13 + Source/Dafny/Cloner.cs | 14 +- Source/Dafny/Compiler.cs | 11 + Source/Dafny/DafnyAst.cs | 172 +++++++- Source/Dafny/Resolver.cs | 562 ++++++++++++++++----------- Test/dafny0/AssumptionVariables0.dfy.expect | 4 +- Test/dafny0/CallStmtTests.dfy | 34 +- Test/dafny0/CallStmtTests.dfy.expect | 4 +- Test/dafny0/DiscoverBounds.dfy.expect | 6 +- Test/dafny0/NonGhostQuantifiers.dfy | 7 + Test/dafny0/NonGhostQuantifiers.dfy.expect | 22 +- Test/dafny0/ParallelResolveErrors.dfy | 13 +- Test/dafny0/ParallelResolveErrors.dfy.expect | 36 +- Test/dafny0/ResolutionErrors.dfy | 278 +++++++++++-- Test/dafny0/ResolutionErrors.dfy.expect | 87 +++-- Test/dafny0/TypeTests.dfy | 50 +-- Test/dafny0/TypeTests.dfy.expect | 14 +- Test/dafny4/set-compr.dfy.expect | 4 +- 18 files changed, 925 insertions(+), 406 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Binaries/DafnyRuntime.cs b/Binaries/DafnyRuntime.cs index d1a3c092..4dda19fe 100644 --- a/Binaries/DafnyRuntime.cs +++ b/Binaries/DafnyRuntime.cs @@ -1012,6 +1012,12 @@ namespace Dafny return pred(false) || pred(true); } } + public static bool QuantChar(bool frall, System.Predicate pred) { + for (int i = 0; i < 0x10000; i++) { + if (pred((char)i) != frall) { return !frall; } + } + return frall; + } public static bool QuantInt(BigInteger lo, BigInteger hi, bool frall, System.Predicate pred) { for (BigInteger i = lo; i < hi; i++) { if (pred(i) != frall) { return !frall; } @@ -1051,6 +1057,13 @@ namespace Dafny yield return true; } } + public static IEnumerable AllChars { + get { + for (int i = 0; i < 0x10000; i++) { + yield return (char)i; + } + } + } public static IEnumerable AllIntegers { get { yield return new BigInteger(0); diff --git a/Source/Dafny/Cloner.cs b/Source/Dafny/Cloner.cs index dd2eed69..032e30a0 100644 --- a/Source/Dafny/Cloner.cs +++ b/Source/Dafny/Cloner.cs @@ -550,13 +550,21 @@ namespace Microsoft.Dafny r = new ForallStmt(Tok(s.Tok), Tok(s.EndTok), s.BoundVars.ConvertAll(CloneBoundVar), null, CloneExpr(s.Range), s.Ens.ConvertAll(CloneMayBeFreeExpr), CloneStmt(s.Body)); } else if (stmt is CalcStmt) { - var s = (CalcStmt)stmt; - r = new CalcStmt(Tok(s.Tok), Tok(s.EndTok), CloneCalcOp(s.Op), s.Lines.ConvertAll(CloneExpr), s.Hints.ConvertAll(CloneBlockStmt), s.StepOps.ConvertAll(CloneCalcOp), CloneCalcOp(s.ResultOp), CloneAttributes(s.Attributes)); + var s = (CalcStmt)stmt; + // calc statements have the unusual property that the last line is duplicated. If that is the case (which + // we expect it to be here), we share the clone of that line as well. + var lineCount = s.Lines.Count; + var lines = new List(lineCount); + for (int i = 0; i < lineCount; i++) { + lines.Add(i == lineCount - 1 && 2 <= lineCount && s.Lines[i] == s.Lines[i - 1] ? lines[i - 1] : CloneExpr(s.Lines[i])); + } + Contract.Assert(lines.Count == lineCount); + r = new CalcStmt(Tok(s.Tok), Tok(s.EndTok), CloneCalcOp(s.Op), lines, s.Hints.ConvertAll(CloneBlockStmt), s.StepOps.ConvertAll(CloneCalcOp), CloneCalcOp(s.ResultOp), CloneAttributes(s.Attributes)); } else if (stmt is MatchStmt) { var s = (MatchStmt)stmt; r = new MatchStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Source), - s.Cases.ConvertAll(CloneMatchCaseStmt), s.UsesOptionalBraces); + s.Cases.ConvertAll(CloneMatchCaseStmt), s.UsesOptionalBraces); } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs index 477acabf..cdd968cf 100644 --- a/Source/Dafny/Compiler.cs +++ b/Source/Dafny/Compiler.cs @@ -1566,6 +1566,9 @@ namespace Microsoft.Dafny { if (bound is ComprehensionExpr.BoolBoundedPool) { Indent(ind); wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName); + } else if (bound is ComprehensionExpr.CharBoundedPool) { + Indent(ind); + wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; Indent(ind); @@ -1777,6 +1780,8 @@ namespace Microsoft.Dafny { Indent(ind); if (bound is ComprehensionExpr.BoolBoundedPool) { wr.WriteLine("foreach (var {0} in Dafny.Helpers.AllBooleans) {{ @{1} = {0};", tmpVar, bv.CompileName); + } else if (bound is ComprehensionExpr.CharBoundedPool) { + wr.WriteLine("foreach (var {0} in Dafny.Helpers.AllChars) {{ @{1} = {0};", tmpVar, bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; if (AsNativeType(bv.Type) != null) { @@ -2831,6 +2836,8 @@ namespace Microsoft.Dafny { // emit: Dafny.Helpers.QuantX(boundsInformation, isForall, bv => body) if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("Dafny.Helpers.QuantBool("); + } else if (bound is ComprehensionExpr.CharBoundedPool) { + wr.Write("Dafny.Helpers.QuantChar("); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; wr.Write("Dafny.Helpers.QuantInt("); @@ -2898,6 +2905,8 @@ namespace Microsoft.Dafny { var bv = e.BoundVars[i]; if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName); + } else if (bound is ComprehensionExpr.CharBoundedPool) { + wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; if (AsNativeType(bv.Type) != null) { @@ -2971,6 +2980,8 @@ namespace Microsoft.Dafny { var bv = e.BoundVars[0]; if (bound is ComprehensionExpr.BoolBoundedPool) { wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName); + } else if (bound is ComprehensionExpr.CharBoundedPool) { + wr.Write("foreach (var @{0} in Dafny.Helpers.AllChars) {{ ", bv.CompileName); } else if (bound is ComprehensionExpr.IntBoundedPool) { var b = (ComprehensionExpr.IntBoundedPool)bound; if (AsNativeType(bv.Type) != null) { diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs index 2a98d5c2..b460d9b4 100644 --- a/Source/Dafny/DafnyAst.cs +++ b/Source/Dafny/DafnyAst.cs @@ -509,6 +509,27 @@ namespace Microsoft.Dafny { } } + public bool HasFinitePossibleValues { + get { + if (IsBoolType || IsCharType || IsRefType) { + return true; + } + var st = AsSetType; + if (st != null && st.Arg.HasFinitePossibleValues) { + return true; + } + var mt = AsMapType; + if (mt != null && mt.Domain.HasFinitePossibleValues) { + return true; + } + var dt = AsDatatype; + if (dt != null && dt.HasFinitePossibleValues) { + return true; + } + return false; + } + } + public CollectionType AsCollectionType { get { return NormalizeExpand() as CollectionType; } } public SetType AsSetType { get { return NormalizeExpand() as SetType; } } public MultiSetType AsMultiSetType { get { return NormalizeExpand() as MultiSetType; } } @@ -2376,6 +2397,48 @@ namespace Microsoft.Dafny { YieldCountVariable.type = YieldCountVariable.OptionalType; // resolve YieldCountVariable here } + /// + /// Returns the non-null expressions of this declaration proper (that is, do not include the expressions of substatements). + /// Does not include the generated class members. + /// + public virtual IEnumerable SubExpressions { + get { + foreach (var e in Attributes.SubExpressions(Attributes)) { + yield return e; + } + foreach (var e in Attributes.SubExpressions(Reads.Attributes)) { + yield return e; + } + foreach (var e in Reads.Expressions) { + yield return e.E; + } + foreach (var e in Attributes.SubExpressions(Modifies.Attributes)) { + yield return e; + } + foreach (var e in Modifies.Expressions) { + yield return e.E; + } + foreach (var e in Attributes.SubExpressions(Decreases.Attributes)) { + yield return e; + } + foreach (var e in Decreases.Expressions) { + yield return e; + } + foreach (var e in Requires) { + yield return e.E; + } + foreach (var e in Ensures) { + yield return e.E; + } + foreach (var e in YieldRequires) { + yield return e.E; + } + foreach (var e in YieldEnsures) { + yield return e.E; + } + } + } + /// /// This Dafny type exists only for the purpose of giving the yield-count variable a type, so /// that the type can be recognized during translation of Dafny into Boogie. It represents @@ -2475,6 +2538,11 @@ namespace Microsoft.Dafny { return EnclosingClass.FullCompileName + ".@" + CompileName; } } + public virtual IEnumerable SubExpressions { + get { + yield break; + } + } } public class Field : MemberDecl { @@ -2999,6 +3067,26 @@ namespace Microsoft.Dafny { public bool IsBuiltin; public Function OverriddenFunction; + public override IEnumerable SubExpressions { + get { + foreach (var e in Req) { + yield return e; + } + foreach (var e in Reads) { + yield return e.E; + } + foreach (var e in Ens) { + yield return e; + } + foreach (var e in Decreases.Expressions) { + yield return e; + } + if (Body != null) { + yield return Body; + } + } + } + public Type Type { get { // Note, the following returned type can contain type parameters from the function and its enclosing class @@ -3213,6 +3301,24 @@ namespace Microsoft.Dafny { public readonly ISet AssignedAssumptionVariables = new HashSet(); public Method OverriddenMethod; + public override IEnumerable SubExpressions { + get { + foreach (var e in Req) { + yield return e.E; + } + foreach (var e in Mod.Expressions) { + yield return e.E; + } + foreach (var e in Ens) { + yield return e.E; + } + foreach (var e in Decreases.Expressions) { + yield return e; + } + } + } + + [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(TypeArgs)); @@ -4821,18 +4927,32 @@ namespace Microsoft.Dafny { } public override IEnumerable SubExpressions { - get { // FIXME: This can return duplicates; this could confuse BottomUpVisitors that modify the AST in place + get { foreach (var e in base.SubExpressions) { yield return e; } foreach (var e in Attributes.SubExpressions(Attributes)) { yield return e; } - - foreach (var l in Lines) { - yield return l; + + for (int i = 0; i < Lines.Count - 1; i++) { // note, we skip the duplicated line at the end + yield return Lines[i]; } - foreach (var e in Steps) { - yield return e; + foreach (var calcop in AllCalcOps) { + var o3 = calcop as TernaryCalcOp; + if (o3 != null) { + yield return o3.Index; + } + } + } + } + + IEnumerable AllCalcOps { + get { + if (Op != null) { + yield return Op; } - if (Result != null) { - yield return Result; + foreach (var stepop in StepOps) { + yield return stepop; + } + if (ResultOp != null) { + yield return ResultOp; } } } @@ -6637,7 +6757,7 @@ namespace Microsoft.Dafny { public readonly Expression Body; public readonly bool Exact; // Exact==true means a regular let expression; Exact==false means an assign-such-that expression public readonly Attributes Attributes; - public List Constraint_Bounds; // initialized and filled in by resolver; null for Exact=true and for a ghost statement + public List Constraint_Bounds; // initialized and filled in by resolver; null for Exact=true and for when expression is in a ghost context // invariant Constraint_Bounds == null || Constraint_Bounds.Count == BoundVars.Count; public List Constraint_MissingBounds; // filled in during resolution; remains "null" if Exact==true or if bounds can be found // invariant Constraint_Bounds == null || Constraint_MissingBounds == null; @@ -6790,6 +6910,22 @@ namespace Microsoft.Dafny { return 5; } } + public class CharBoundedPool : BoundedPool + { + public override int Preference() { + return 4; + } + } + public class RefBoundedPool : BoundedPool + { + public Type Type; + public RefBoundedPool(Type t) { + Type = t; + } + public override int Preference() { + return 2; + } + } public class IntBoundedPool : BoundedPool { public readonly Expression LowerBound; @@ -6864,6 +7000,24 @@ namespace Microsoft.Dafny { public List MissingBounds; // filled in during resolution; remains "null" if bounds can be found // invariant Bounds == null || MissingBounds == null; + public List UncompilableBoundVars() { + var bvs = new List(); + if (MissingBounds != null) { + bvs.AddRange(MissingBounds); + } + if (Bounds != null) { + Contract.Assert(Bounds.Count == BoundVars.Count); + for (int i = 0; i < Bounds.Count; i++) { + var bound = Bounds[i]; + if (bound is RefBoundedPool) { + // yes, this is in principle a bound, but it's not one we'd like to compile + bvs.Add(BoundVars[i]); + } + } + } + return bvs; + } + public ComprehensionExpr(IToken tok, List bvars, Expression range, Expression term, Attributes attrs) : base(tok) { Contract.Requires(tok != null); diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index d82d7d1f..ec3a69c9 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -1313,16 +1313,6 @@ namespace Microsoft.Dafny } } - private readonly List needFiniteBoundsChecks_SetComprehension = new List(); - private readonly List needBoundsDiscovery_AssignSuchThatStmt = new List(); - private readonly List needFiniteBoundsChecks_LetSuchThatExpr = new List(); - public int NFBC_Count { - // provided just for the purpose of conveniently writing contracts for ResolveTopLevelDecl_Meat - get { - return needFiniteBoundsChecks_SetComprehension.Count + needFiniteBoundsChecks_LetSuchThatExpr.Count; - } - } - static readonly List NativeTypes = new List() { new NativeType("byte", 0, 0x100, "", true), new NativeType("sbyte", -0x80, 0x80, "", true), @@ -1338,13 +1328,23 @@ namespace Microsoft.Dafny Contract.Requires(declarations != null); Contract.Requires(cce.NonNullElements(datatypeDependencies)); Contract.Requires(cce.NonNullElements(codatatypeDependencies)); - Contract.Requires(NFBC_Count == 0); Contract.Requires(AllTypeConstraints.Count == 0); - Contract.Ensures(NFBC_Count == 0); Contract.Ensures(AllTypeConstraints.Count == 0); int prevErrorCount = reporter.Count(ErrorLevel.Error); + // ---------------------------------- Pass 0 ---------------------------------- + // This pass resolves names, introduces (and may solve) type constraints, and + // builds the module's call graph. + // Some bounds are discovered during this pass [is this necessary? can they be + // moved to pass 1 like the other bounds discovery? --KRML], namely: + // - forall statements + // - quantifier expressions + // - map comprehensions + // For 'newtype' declarations, it also checks that all types were fully + // determined. + // ---------------------------------------------------------------------------- + // Resolve the meat of classes and iterators, the definitions of type synonyms, and the type parameters of all top-level type declarations // First, resolve the newtype declarations and the constraint clauses, including filling in .ResolvedOp fields. This is needed for the // resolution of the other declarations, because those other declarations may invoke DiscoverBounds, which looks at the .Constraint field @@ -1403,172 +1403,80 @@ namespace Microsoft.Dafny allTypeParameters.PopMarker(); } + // ---------------------------------- Pass 1 ---------------------------------- + // This pass: + // * checks that type inference was able to determine all types + // * fills in the .ResolvedOp field of binary expressions + // * discovers bounds for: + // - set comprehensions + // - assign-such-that statements + // - compilable let-such-that expressions + // - newtype constraints + // For each statement body that it successfully typed, this pass also: + // * computes ghost interests + // * determines/checks tail-recursion. + // ---------------------------------------------------------------------------- + Dictionary nativeTypeMap = new Dictionary(); foreach (var nativeType in NativeTypes) { nativeTypeMap.Add(nativeType.Name, nativeType); } - if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // Check that type inference went well everywhere; this will also fill in the .ResolvedOp field in binary expressions foreach (TopLevelDecl d in declarations) { if (d is IteratorDecl) { var iter = (IteratorDecl)d; + var prevErrCnt = reporter.Count(ErrorLevel.Error); iter.Members.Iter(CheckTypeInference_Member); + if (prevErrCnt == reporter.Count(ErrorLevel.Error)) { + iter.SubExpressions.Iter(e => CheckExpression(e, this, iter)); + } if (iter.Body != null) { CheckTypeInference(iter.Body); + if (prevErrCnt == reporter.Count(ErrorLevel.Error)) { + ComputeGhostInterest(iter.Body, false, iter); + CheckExpression(iter.Body, this, iter); + } } } else if (d is ClassDecl) { var cl = (ClassDecl)d; - cl.Members.Iter(CheckTypeInference_Member); foreach (var member in cl.Members) { - var m = member as Method; - if (m != null && m.Body != null) { - DetermineTailRecursion(m); + var prevErrCnt = reporter.Count(ErrorLevel.Error); + CheckTypeInference_Member(member); + if (prevErrCnt == reporter.Count(ErrorLevel.Error)) { + if (member is Method) { + var m = (Method)member; + if (m.Body != null) { + ComputeGhostInterest(m.Body, m.IsGhost, m); + CheckExpression(m.Body, this, m); + DetermineTailRecursion(m); + } + } else if (member is Function) { + var f = (Function)member; + if (!f.IsGhost && f.Body != null) { + CheckIsNonGhost(f.Body); + } + DetermineTailRecursion(f); + } + if (prevErrCnt == reporter.Count(ErrorLevel.Error) && member is ICodeContext) { + member.SubExpressions.Iter(e => CheckExpression(e, this, (ICodeContext)member)); + } } } } else if (d is NewtypeDecl) { var dd = (NewtypeDecl)d; - bool? boolNativeType = null; - NativeType stringNativeType = null; - object nativeTypeAttr = true; - bool hasNativeTypeAttr = Attributes.ContainsMatchingValue(dd.Attributes, "nativeType", ref nativeTypeAttr, - new Attributes.MatchingValueOption[] { - Attributes.MatchingValueOption.Empty, - Attributes.MatchingValueOption.Bool, - Attributes.MatchingValueOption.String }, - err => reporter.Error(MessageSource.Resolver, dd, err)); - if (hasNativeTypeAttr) { - if (nativeTypeAttr is bool) { - boolNativeType = (bool)nativeTypeAttr; - } else { - string keyString = (string)nativeTypeAttr; - if (nativeTypeMap.ContainsKey(keyString)) { - stringNativeType = nativeTypeMap[keyString]; - } else { - reporter.Error(MessageSource.Resolver, dd, "Unsupported nativeType {0}", keyString); - } - } - } - if (stringNativeType != null || boolNativeType == true) { - if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) { - reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used on integral types"); - } - if (dd.Var == null) { - reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used if newtype specifies a constraint"); - } - } if (dd.Var != null) { Contract.Assert(dd.Constraint != null); - CheckTypeInference(dd.Constraint); - - Func GetConst = null; - GetConst = (Expression e) => { - int m = 1; - BinaryExpr bin = e as BinaryExpr; - if (bin != null && bin.Op == BinaryExpr.Opcode.Sub && GetConst(bin.E0) == BigInteger.Zero) { - m = -1; - e = bin.E1; - } - LiteralExpr l = e as LiteralExpr; - if (l != null && l.Value is BigInteger) { - return m * (BigInteger)l.Value; - } - return null; - }; - var bounds = DiscoverAllBounds_SingleVar(dd.Var, dd.Constraint); - List potentialNativeTypes = - (stringNativeType != null) ? new List { stringNativeType } : - (boolNativeType == false) ? new List() : - NativeTypes; - foreach (var nt in potentialNativeTypes) { - bool lowerOk = false; - bool upperOk = false; - foreach (var bound in bounds) { - if (bound is ComprehensionExpr.IntBoundedPool) { - var bnd = (ComprehensionExpr.IntBoundedPool)bound; - if (bnd.LowerBound != null) { - BigInteger? lower = GetConst(bnd.LowerBound); - if (lower != null && nt.LowerBound <= lower) { - lowerOk = true; - } - } - if (bnd.UpperBound != null) { - BigInteger? upper = GetConst(bnd.UpperBound); - if (upper != null && upper <= nt.UpperBound) { - upperOk = true; - } - } - } - } - if (lowerOk && upperOk) { - dd.NativeType = nt; - break; - } - } - if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) { - reporter.Error(MessageSource.Resolver, dd, "Dafny's heuristics cannot find a compatible native type. " + - "Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'"); - } - if (dd.NativeType != null && stringNativeType == null) { - reporter.Info(MessageSource.Resolver, dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}"); - } + CheckExpression(dd.Constraint, this, dd); } + FigureOutNativeType(dd, nativeTypeMap); } } } - if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - // At this point, it is necessary to know for each statement and expression if it is ghost or not - foreach (var e in needFiniteBoundsChecks_SetComprehension) { - CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.Range, true, true, out missingBounds); - if (missingBounds.Count != 0) { - e.MissingBounds = missingBounds; - if (e.Finite) { - foreach (var bv in e.MissingBounds) { - reporter.Error(MessageSource.Resolver, e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - } - } - } - foreach (AssignSuchThatStmt s in needBoundsDiscovery_AssignSuchThatStmt) { - Contract.Assert(!s.IsGhost); - var varLhss = new List(); - foreach (var lhs in s.Lhss) { - var ide = (IdentifierExpr)lhs.Resolved; // successful resolution above implies all LHS's are IdentifierExpr's - varLhss.Add(ide.Var); - } - - List missingBounds; - var bestBounds = DiscoverBestBounds_MultipleVars(varLhss, s.Expr, true, false, out missingBounds); - if (missingBounds.Count != 0) { - s.MissingBounds = missingBounds; // so that an error message can be produced during compilation - } else { - Contract.Assert(bestBounds != null); - s.Bounds = bestBounds; - } - } - foreach (var e in needFiniteBoundsChecks_LetSuchThatExpr) { - Contract.Assert(!e.Exact); // only let-such-that expressions are ever added to the list - Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully - var constraint = e.RHSs[0]; - CheckTypeInference(constraint); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - var vars = new List(e.BoundVars); - var bestBounds = DiscoverBestBounds_MultipleVars(vars, constraint, true, false, out missingBounds); - if (missingBounds.Count != 0) { - e.Constraint_MissingBounds = missingBounds; - foreach (var bv in e.Constraint_MissingBounds) { - reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - } else { - e.Constraint_Bounds = bestBounds; - } - } - } - needFiniteBoundsChecks_SetComprehension.Clear(); - needFiniteBoundsChecks_LetSuchThatExpr.Clear(); + // ---------------------------------- Pass 2 ---------------------------------- + // This pass fills in various additional information. + // ---------------------------------------------------------------------------- if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // fill in the postconditions and bodies of prefix lemmas @@ -1894,6 +1802,93 @@ namespace Microsoft.Dafny } } + private void FigureOutNativeType(NewtypeDecl dd, Dictionary nativeTypeMap) { + Contract.Requires(dd != null); + Contract.Requires(nativeTypeMap != null); + bool? boolNativeType = null; + NativeType stringNativeType = null; + object nativeTypeAttr = true; + bool hasNativeTypeAttr = Attributes.ContainsMatchingValue(dd.Attributes, "nativeType", ref nativeTypeAttr, + new Attributes.MatchingValueOption[] { + Attributes.MatchingValueOption.Empty, + Attributes.MatchingValueOption.Bool, + Attributes.MatchingValueOption.String }, + err => reporter.Error(MessageSource.Resolver, dd, err)); + if (hasNativeTypeAttr) { + if (nativeTypeAttr is bool) { + boolNativeType = (bool)nativeTypeAttr; + } else { + string keyString = (string)nativeTypeAttr; + if (nativeTypeMap.ContainsKey(keyString)) { + stringNativeType = nativeTypeMap[keyString]; + } else { + reporter.Error(MessageSource.Resolver, dd, "Unsupported nativeType {0}", keyString); + } + } + } + if (stringNativeType != null || boolNativeType == true) { + if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) { + reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used on integral types"); + } + if (dd.Var == null) { + reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used if newtype specifies a constraint"); + } + } + if (dd.Var != null) { + Func GetConst = null; + GetConst = (Expression e) => { + int m = 1; + BinaryExpr bin = e as BinaryExpr; + if (bin != null && bin.Op == BinaryExpr.Opcode.Sub && GetConst(bin.E0) == BigInteger.Zero) { + m = -1; + e = bin.E1; + } + LiteralExpr l = e as LiteralExpr; + if (l != null && l.Value is BigInteger) { + return m * (BigInteger)l.Value; + } + return null; + }; + var bounds = DiscoverAllBounds_SingleVar(dd.Var, dd.Constraint); + List potentialNativeTypes = + (stringNativeType != null) ? new List { stringNativeType } : + (boolNativeType == false) ? new List() : + NativeTypes; + foreach (var nt in potentialNativeTypes) { + bool lowerOk = false; + bool upperOk = false; + foreach (var bound in bounds) { + if (bound is ComprehensionExpr.IntBoundedPool) { + var bnd = (ComprehensionExpr.IntBoundedPool)bound; + if (bnd.LowerBound != null) { + BigInteger? lower = GetConst(bnd.LowerBound); + if (lower != null && nt.LowerBound <= lower) { + lowerOk = true; + } + } + if (bnd.UpperBound != null) { + BigInteger? upper = GetConst(bnd.UpperBound); + if (upper != null && upper <= nt.UpperBound) { + upperOk = true; + } + } + } + } + if (lowerOk && upperOk) { + dd.NativeType = nt; + break; + } + } + if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) { + reporter.Error(MessageSource.Resolver, dd, "Dafny's heuristics cannot find a compatible native type. " + + "Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'"); + } + if (dd.NativeType != null && stringNativeType == null) { + reporter.Info(MessageSource.Resolver, dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}"); + } + } + } + /// /// Adds the type constraint ty==expected, eventually printing the error message "msg" if this is found to be /// untenable. If this is immediately known not to be untenable, false is returned. @@ -2123,16 +2118,60 @@ namespace Microsoft.Dafny } else if (stmt is ForallStmt) { var s = (ForallStmt)stmt; s.BoundVars.Iter(bv => CheckTypeIsDetermined(bv.tok, bv.Type, "bound variable")); + } else if (stmt is AssignSuchThatStmt) { + var s = (AssignSuchThatStmt)stmt; + if (s.AssumeToken == null) { + var varLhss = new List(); + foreach (var lhs in s.Lhss) { + var ide = (IdentifierExpr)lhs.Resolved; // successful resolution implies all LHS's are IdentifierExpr's + varLhss.Add(ide.Var); + } + List missingBounds; + var bestBounds = DiscoverBestBounds_MultipleVars(varLhss, s.Expr, true, false, out missingBounds); + if (missingBounds.Count != 0) { + s.MissingBounds = missingBounds; // so that an error message can be produced during compilation + } else { + Contract.Assert(bestBounds != null); + s.Bounds = bestBounds; + } + } + } else if (stmt is CalcStmt) { + var s = (CalcStmt)stmt; + // The resolution of the calc statement builds up .Steps and .Result, which are of the form E0 OP E1, where + // E0 and E1 are expressions from .Lines. These additional expressions still need to have their .ResolvedOp + // fields filled in, so we visit them (but not their subexpressions) here. + foreach (var e in s.Steps) { + VisitOneExpr(e); + } + VisitOneExpr(s.Result); } } protected override void VisitOneExpr(Expression expr) { if (expr is ComprehensionExpr) { var e = (ComprehensionExpr)expr; - if (e != null) { - foreach (var bv in e.BoundVars) { - if (!IsDetermined(bv.Type.Normalize())) { - resolver.reporter.Error(MessageSource.Resolver, bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", - bv.Name); + foreach (var bv in e.BoundVars) { + if (!IsDetermined(bv.Type.Normalize())) { + resolver.reporter.Error(MessageSource.Resolver, bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", bv.Name); + } + } + if (e is SetComprehension) { + var sc = (SetComprehension)e; + if (sc.Finite) { + // A set must be finite. Discover bounds for the Range expression, but report an error only if the Term is not + // of a finite-individuals type. + List missingBounds; + sc.Bounds = DiscoverBestBounds_MultipleVars(sc.BoundVars, sc.Range, true, true, out missingBounds); + if (missingBounds.Count != 0) { + sc.MissingBounds = missingBounds; + if (sc.Type.HasFinitePossibleValues) { + // This means the set is finite, regardless of if the Range is bounded. So, we don't give any error here. + // However, if this expression is used in a non-ghost context (which is not yet known at this stage of + // resolution), the resolver will generate an error about that later. + } else { + foreach (var bv in sc.MissingBounds) { + resolver.reporter.Error(MessageSource.Resolver, sc, "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); + } + } } } } @@ -2172,6 +2211,7 @@ namespace Microsoft.Dafny var bin = expr as BinaryExpr; if (bin != null) { bin.ResolvedOp = ResolveOp(bin.Op, bin.E1.Type); + } } } @@ -2249,6 +2289,58 @@ namespace Microsoft.Dafny } #endregion CheckTypeInference + // ------------------------------------------------------------------------------------------------------ + // ----- CheckExpression -------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------------------------------ + #region CheckExpression + /// + /// This method computes ghost interests in the statement portion of StmtExpr's and + /// checks for hint restrictions in any CalcStmt. + /// + void CheckExpression(Expression expr, Resolver resolver, ICodeContext codeContext) { + Contract.Requires(expr != null); + Contract.Requires(resolver != null); + Contract.Requires(codeContext != null); + var v = new CheckExpression_Visitor(resolver, codeContext); + v.Visit(expr); + } + /// + /// This method computes ghost interests in the statement portion of StmtExpr's and + /// checks for hint restrictions in any CalcStmt. + /// + void CheckExpression(Statement stmt, Resolver resolver, ICodeContext codeContext) { + Contract.Requires(stmt != null); + Contract.Requires(resolver != null); + Contract.Requires(codeContext != null); + var v = new CheckExpression_Visitor(resolver, codeContext); + v.Visit(stmt); + } + class CheckExpression_Visitor : ResolverBottomUpVisitor + { + readonly ICodeContext CodeContext; + public CheckExpression_Visitor(Resolver resolver, ICodeContext codeContext) + : base(resolver) { + Contract.Requires(resolver != null); + Contract.Requires(codeContext != null); + CodeContext = codeContext; + } + protected override void VisitOneExpr(Expression expr) { + if (expr is StmtExpr) { + var e = (StmtExpr)expr; + resolver.ComputeGhostInterest(e.S, true, CodeContext); + } + } + protected override void VisitOneStmt(Statement stmt) { + if (stmt is CalcStmt) { + var s = (CalcStmt)stmt; + foreach (var h in s.Hints) { + resolver.CheckHintRestrictions(h, new HashSet()); + } + } + } + } + #endregion + // ------------------------------------------------------------------------------------------------------ // ----- CheckTailRecursive ----------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------------ @@ -3009,11 +3101,11 @@ namespace Microsoft.Dafny // ----- ComputeGhostInterest --------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------------ #region ComputeGhostInterest - public void ComputeGhostInterest(Statement stmt, ICodeContext codeContext) { + public void ComputeGhostInterest(Statement stmt, bool mustBeErasable, ICodeContext codeContext) { Contract.Requires(stmt != null); Contract.Requires(codeContext != null); var visitor = new GhostInterest_Visitor(codeContext, this); - visitor.Visit(stmt, codeContext.IsGhost); + visitor.Visit(stmt, mustBeErasable); } class GhostInterest_Visitor { @@ -3037,12 +3129,6 @@ namespace Microsoft.Dafny Contract.Requires(msgArgs != null); resolver.reporter.Error(MessageSource.Resolver, expr, msg, msgArgs); } - protected void Error(IToken tok, string msg, params object[] msgArgs) { - Contract.Requires(tok != null); - Contract.Requires(msg != null); - Contract.Requires(msgArgs != null); - resolver.reporter.Error(MessageSource.Resolver, tok, msg, msgArgs); - } /// /// This method does three things: /// 0. Reports an error if "mustBeErasable" and the statement assigns to a non-ghost field @@ -3057,6 +3143,7 @@ namespace Microsoft.Dafny /// because break statements look at the ghost status of its enclosing statements. /// public void Visit(Statement stmt, bool mustBeErasable) { + Contract.Requires(stmt != null); Contract.Assume(!codeContext.IsGhost || mustBeErasable); // (this is really a precondition) codeContext.IsGhost ==> mustBeErasable if (stmt is PredicateStmt) { @@ -3107,9 +3194,6 @@ namespace Microsoft.Dafny } } } - if (!s.IsGhost) { - resolver.needBoundsDiscovery_AssignSuchThatStmt.Add(s); - } } else if (stmt is UpdateStmt) { var s = (UpdateStmt)stmt; @@ -3124,13 +3208,6 @@ namespace Microsoft.Dafny local.IsGhost = true; } } - foreach (var local in s.Locals) { - if (Attributes.Contains(local.Attributes, "assumption")) { - if (!local.IsGhost) { - Error(local.Tok, "assumption variable must be ghost"); - } - } - } s.IsGhost = (s.Update == null || s.Update.IsGhost) && s.Locals.All(v => v.IsGhost); if (s.Update != null) { Visit(s.Update, mustBeErasable); @@ -4040,14 +4117,10 @@ namespace Microsoft.Dafny var prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(f.Body, new ResolveOpts(f, false)); SolveAllTypeConstraints(); - if (!f.IsGhost && prevErrorCount == reporter.Count(ErrorLevel.Error)) { - CheckIsNonGhost(f.Body); - } Contract.Assert(f.Body.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(f.Body.Type, f.ResultType, f, "Function body type mismatch (expected {0}, got {1})", f.ResultType, f.Body.Type); } scope.PopMarker(); - DetermineTailRecursion(f); } /// @@ -4187,7 +4260,7 @@ namespace Microsoft.Dafny ResolveBlockStatement(m.Body, m.IsGhost, m); SolveAllTypeConstraints(); if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - ComputeGhostInterest(m.Body, m); +//KRML ComputeGhostInterest(m.Body, m); } } @@ -4308,7 +4381,7 @@ namespace Microsoft.Dafny if (iter.Body != null) { ResolveBlockStatement(iter.Body, false, iter); if (reporter.Count(ErrorLevel.Error) == postSpecErrorCount) { - ComputeGhostInterest(iter.Body, iter); + //KRML ComputeGhostInterest(iter.Body, iter); } } @@ -5290,7 +5363,10 @@ namespace Microsoft.Dafny } if (!(local.Type.IsBoolType)) { - reporter.Error(MessageSource.Resolver, s, "assumption variable must be of type 'bool'"); + reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable must be of type 'bool'"); + } + if (!local.IsGhost) { + reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable must be ghost"); } } } @@ -5599,7 +5675,6 @@ namespace Microsoft.Dafny loopStack = new List(); foreach (var h in s.Hints) { ResolveStatement(h, true, codeContext); - CheckHintRestrictions(h); } labeledStatements = prevLblStmts; loopStack = prevLoopStack; @@ -6347,9 +6422,6 @@ namespace Microsoft.Dafny if (!isInitCall && callee is Constructor) { reporter.Error(MessageSource.Resolver, s, "a constructor is allowed to be called only when an object is being allocated"); } - if (specContextOnly && !callee.IsGhost) { - reporter.Error(MessageSource.Resolver, s, "only ghost methods can be called from this context"); - } // resolve left-hand sides foreach (var lhs in s.Lhs) { @@ -6633,8 +6705,9 @@ namespace Microsoft.Dafny /// Check that a statment is a valid hint for a calculation. /// ToDo: generalize the part for compound statements to take a delegate? /// - public void CheckHintRestrictions(Statement stmt) { + public void CheckHintRestrictions(Statement stmt, ISet localsAllowedInUpdates) { Contract.Requires(stmt != null); + Contract.Requires(localsAllowedInUpdates != null); if (stmt is PredicateStmt) { // cool } else if (stmt is PrintStmt) { @@ -6648,11 +6721,11 @@ namespace Microsoft.Dafny } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; foreach (var lhs in s.Lhss) { - CheckHintLhs(s.Tok, lhs.Resolved); + CheckHintLhs(s.Tok, lhs.Resolved, localsAllowedInUpdates); } } else if (stmt is AssignStmt) { var s = (AssignStmt)stmt; - CheckHintLhs(s.Tok, s.Lhs.Resolved); + CheckHintLhs(s.Tok, s.Lhs.Resolved, localsAllowedInUpdates); } else if (stmt is CallStmt) { var s = (CallStmt)stmt; if (s.Method.Mod.Expressions.Count != 0) { @@ -6661,33 +6734,33 @@ namespace Microsoft.Dafny } else if (stmt is UpdateStmt) { var s = (UpdateStmt)stmt; foreach (var ss in s.ResolvedStatements) { - CheckHintRestrictions(ss); + CheckHintRestrictions(ss, localsAllowedInUpdates); } } else if (stmt is VarDeclStmt) { var s = (VarDeclStmt)stmt; + s.Locals.Iter(local => localsAllowedInUpdates.Add(local)); if (s.Update != null) { - CheckHintRestrictions(s.Update); + CheckHintRestrictions(s.Update, localsAllowedInUpdates); } } else if (stmt is BlockStmt) { var s = (BlockStmt)stmt; - scope.PushMarker(); + var newScopeForLocals = new HashSet(localsAllowedInUpdates); foreach (var ss in s.Body) { - CheckHintRestrictions(ss); + CheckHintRestrictions(ss, newScopeForLocals); } - scope.PopMarker(); } else if (stmt is IfStmt) { var s = (IfStmt)stmt; - CheckHintRestrictions(s.Thn); + CheckHintRestrictions(s.Thn, localsAllowedInUpdates); if (s.Els != null) { - CheckHintRestrictions(s.Els); + CheckHintRestrictions(s.Els, localsAllowedInUpdates); } } else if (stmt is AlternativeStmt) { var s = (AlternativeStmt)stmt; foreach (var alt in s.Alternatives) { foreach (var ss in alt.Body) { - CheckHintRestrictions(ss); + CheckHintRestrictions(ss, localsAllowedInUpdates); } } @@ -6697,14 +6770,14 @@ namespace Microsoft.Dafny reporter.Error(MessageSource.Resolver, s.Mod.Expressions[0].tok, "a while statement used inside a hint is not allowed to have a modifies clause"); } if (s.Body != null) { - CheckHintRestrictions(s.Body); + CheckHintRestrictions(s.Body, localsAllowedInUpdates); } } else if (stmt is AlternativeLoopStmt) { var s = (AlternativeLoopStmt)stmt; foreach (var alt in s.Alternatives) { foreach (var ss in alt.Body) { - CheckHintRestrictions(ss); + CheckHintRestrictions(ss, localsAllowedInUpdates); } } @@ -6726,14 +6799,14 @@ namespace Microsoft.Dafny } else if (stmt is CalcStmt) { var s = (CalcStmt)stmt; foreach (var h in s.Hints) { - CheckHintRestrictions(h); + CheckHintRestrictions(h, new HashSet()); } } else if (stmt is MatchStmt) { var s = (MatchStmt)stmt; foreach (var kase in s.Cases) { foreach (var ss in kase.Body) { - CheckHintRestrictions(ss); + CheckHintRestrictions(ss, localsAllowedInUpdates); } } @@ -6742,11 +6815,14 @@ namespace Microsoft.Dafny } } - void CheckHintLhs(IToken tok, Expression lhs) { + void CheckHintLhs(IToken tok, Expression lhs, ISet localsAllowedInUpdates) { + Contract.Requires(tok != null); + Contract.Requires(lhs != null); + Contract.Requires(localsAllowedInUpdates != null); var idExpr = lhs as IdentifierExpr; if (idExpr == null) { reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update heap locations"); - } else if (scope.ContainsDecl(idExpr.Var)) { + } else if (!localsAllowedInUpdates.Contains(idExpr.Var)) { reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update a variable declared outside the hint"); } } @@ -7768,9 +7844,6 @@ namespace Microsoft.Dafny ResolveExpression(rhs, opts); ConstrainTypes(rhs.Type, Type.Bool, rhs.tok, "type of RHS of let-such-that expression must be boolean (got {0})", rhs.Type); } - if (!opts.DontCareAboutCompilation && !e.BoundVars.All(bv => bv.IsGhost)) { - needFiniteBoundsChecks_LetSuchThatExpr.Add(e); - } } ResolveExpression(e.Body, opts); ResolveAttributes(e.Attributes, new ResolveOpts(opts, true)); @@ -7819,21 +7892,17 @@ namespace Microsoft.Dafny List missingBounds; e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.LogicalBody(), e is ExistsExpr, true, out missingBounds); if (missingBounds.Count != 0) { - // Report errors here about quantifications that depend on the allocation state. - var mb = missingBounds; - if (opts.codeContext is Function) { - mb = new List(); // (who cares if we allocate another array; this happens only in the case of a resolution error anyhow) - foreach (var bv in missingBounds) { - if (bv.Type.IsRefType) { - reporter.Error(MessageSource.Resolver, expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name); - } else { - mb.Add(bv); - } + e.MissingBounds = missingBounds; + } + if (opts.codeContext is Function && e.Bounds != null) { + Contract.Assert(e.Bounds.Count == e.BoundVars.Count); + for (int i = 0; i < e.Bounds.Count; i++) { + var bound = e.Bounds[i] as ComprehensionExpr.RefBoundedPool; + if (bound != null) { + var bv = e.BoundVars[i]; + reporter.Error(MessageSource.Resolver, expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name); } } - if (mb.Count != 0) { - e.MissingBounds = mb; - } } } @@ -7855,12 +7924,6 @@ namespace Microsoft.Dafny scope.PopMarker(); expr.Type = new SetType(e.Finite, e.Term.Type); - if (opts.DontCareAboutCompilation && (e.Term.Type.IsRefType || e.Term.Type.IsBoolType) || e.Term.Type.IsCharType) { - // ok, term type is finite and we're in a ghost context - } else { - needFiniteBoundsChecks_SetComprehension.Add(e); - } - } else if (expr is MapComprehension) { var e = (MapComprehension)expr; int prevErrorCount = reporter.Count(ErrorLevel.Error); @@ -9329,17 +9392,47 @@ namespace Microsoft.Dafny CheckIsNonGhost(e.RHSs[0]); } CheckIsNonGhost(e.Body); + + // fill in bounds for this to-be-compiled let-such-that expression + Contract.Assert(e.RHSs.Count == 1); // if we got this far, the resolver will have checked this condition successfully + var constraint = e.RHSs[0]; + List missingBounds; + var vars = new List(e.BoundVars); + var bestBounds = DiscoverBestBounds_MultipleVars(vars, constraint, true, false, out missingBounds); + if (missingBounds.Count != 0) { + e.Constraint_MissingBounds = missingBounds; + foreach (var bv in e.Constraint_MissingBounds) { + reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + } + } else { + e.Constraint_Bounds = bestBounds; + } } return; - } else if (expr is QuantifierExpr) { - var e = (QuantifierExpr)expr; - Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution - if (e.MissingBounds != null) { - foreach (var bv in e.MissingBounds) { - reporter.Error(MessageSource.Resolver, expr, "quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + } else if (expr is LambdaExpr) { + var e = expr as LambdaExpr; + CheckIsNonGhost(e.Body); + return; + } else if (expr is ComprehensionExpr) { + var e = (ComprehensionExpr)expr; + var uncompilableBoundVars = e.UncompilableBoundVars(); + if (uncompilableBoundVars.Count != 0) { + string what; + if (e is SetComprehension) { + what = "set comprehensions"; + } else if (e is MapComprehension) { + what = "map comprehensions"; + } else { + Contract.Assume(e is QuantifierExpr); // otherwise, unexpected ComprehensionExpr (since LambdaExpr is handled separately above) + Contract.Assert(((QuantifierExpr)e).SplitQuantifier == null); // No split quantifiers during resolution + what = "quantifiers"; + } + foreach (var bv in uncompilableBoundVars) { + reporter.Error(MessageSource.Resolver, expr, "{0} in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for '{1}'", what, bv.Name); } return; } + } else if (expr is MapComprehension) { var e = (MapComprehension)expr; if (e.MissingBounds != null && !e.Finite) { @@ -9358,10 +9451,6 @@ namespace Microsoft.Dafny var e = (ChainingExpression)expr; e.Operands.ForEach(CheckIsNonGhost); return; - } else if (expr is LambdaExpr) { - var e = expr as LambdaExpr; - CheckIsNonGhost(e.Body); - return; } foreach (var ee in expr.SubExpressions) { @@ -9520,8 +9609,11 @@ namespace Microsoft.Dafny // Maybe the type itself gives a bound if (bv.Type.IsBoolType) { - // easy bounds.Add(new ComprehensionExpr.BoolBoundedPool()); + } else if (bv.Type.IsCharType) { + bounds.Add(new ComprehensionExpr.CharBoundedPool()); + } else if (bv.Type.IsRefType) { + bounds.Add(new ComprehensionExpr.RefBoundedPool(bv.Type)); } else if (bv.Type.IsIndDatatype && bv.Type.AsIndDatatype.HasFinitePossibleValues) { bounds.Add(new ComprehensionExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype)); } else if (bv.Type.IsNumericBased(Type.NumericPersuation.Int)) { diff --git a/Test/dafny0/AssumptionVariables0.dfy.expect b/Test/dafny0/AssumptionVariables0.dfy.expect index 16572961..83eb8a73 100644 --- a/Test/dafny0/AssumptionVariables0.dfy.expect +++ b/Test/dafny0/AssumptionVariables0.dfy.expect @@ -1,13 +1,13 @@ AssumptionVariables0.dfy(6,29): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " AssumptionVariables0.dfy(7,33): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a2 && " -AssumptionVariables0.dfy(9,2): Error: assumption variable must be of type 'bool' +AssumptionVariables0.dfy(9,26): Error: assumption variable must be of type 'bool' AssumptionVariables0.dfy(15,5): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a3 && " AssumptionVariables0.dfy(17,5): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a3 && " AssumptionVariables0.dfy(27,5): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " AssumptionVariables0.dfy(31,5): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " AssumptionVariables0.dfy(53,9): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " AssumptionVariables0.dfy(61,37): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " -AssumptionVariables0.dfy(61,10): Error: assumption variable must be of type 'bool' +AssumptionVariables0.dfy(61,34): Error: assumption variable must be of type 'bool' AssumptionVariables0.dfy(69,15): Error: there may be at most one assignment to an assumption variable, the RHS of which must match the expression "a0 && " AssumptionVariables0.dfy(78,20): Error: assumption variable must be ghost 12 resolution/type errors detected in AssumptionVariables0.dfy diff --git a/Test/dafny0/CallStmtTests.dfy b/Test/dafny0/CallStmtTests.dfy index 67e66b34..46c466ff 100644 --- a/Test/dafny0/CallStmtTests.dfy +++ b/Test/dafny0/CallStmtTests.dfy @@ -1,23 +1,27 @@ // RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" -method testing1(t: int) -{ - t := m(); // error: should be checked at the Dafny level, not fall to Boogie. -} +module M0 { + method testing1(t: int) + { + t := m(); // error: should be checked at the Dafny level, not fall to Boogie. + } -method m() returns (r: int) -{ - return 3; + method m() returns (r: int) + { + return 3; + } } -method testing2() -{ - var v; - v := m2(); // error: v needs to be ghost because r is. -} +module M1 { + method testing2() + { + var v; + v := m2(); // error: v needs to be ghost because r is. + } -method m2() returns (ghost r: int) -{ - r := 23; + method m2() returns (ghost r: int) + { + r := 23; + } } diff --git a/Test/dafny0/CallStmtTests.dfy.expect b/Test/dafny0/CallStmtTests.dfy.expect index 8a334754..246b89f8 100644 --- a/Test/dafny0/CallStmtTests.dfy.expect +++ b/Test/dafny0/CallStmtTests.dfy.expect @@ -1,3 +1,3 @@ -CallStmtTests.dfy(6,3): Error: LHS of assignment must denote a mutable variable -CallStmtTests.dfy(17,10): Error: actual out-parameter 0 is required to be a ghost variable +CallStmtTests.dfy(7,4): Error: LHS of assignment must denote a mutable variable +CallStmtTests.dfy(20,11): Error: actual out-parameter 0 is required to be a ghost variable 2 resolution/type errors detected in CallStmtTests.dfy diff --git a/Test/dafny0/DiscoverBounds.dfy.expect b/Test/dafny0/DiscoverBounds.dfy.expect index ee816683..34003053 100644 --- a/Test/dafny0/DiscoverBounds.dfy.expect +++ b/Test/dafny0/DiscoverBounds.dfy.expect @@ -1,4 +1,4 @@ -DiscoverBounds.dfy(36,7): Error: 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 'o'' -DiscoverBounds.dfy(39,7): Error: 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 'r' -DiscoverBounds.dfy(40,7): Error: 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 'r'' +DiscoverBounds.dfy(36,7): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o'' +DiscoverBounds.dfy(39,7): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'r' +DiscoverBounds.dfy(40,7): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'r'' 3 resolution/type errors detected in DiscoverBounds.dfy diff --git a/Test/dafny0/NonGhostQuantifiers.dfy b/Test/dafny0/NonGhostQuantifiers.dfy index bff1d65b..e522d0fc 100644 --- a/Test/dafny0/NonGhostQuantifiers.dfy +++ b/Test/dafny0/NonGhostQuantifiers.dfy @@ -181,6 +181,12 @@ module DependencyOnAllAllocatedObjects { forall c: SomeClass :: true // error: not allowed to dependend on which objects are allocated } + class SomeClass { + var f: int; + } +} + +module DependencyOnAllAllocatedObjects_More { method M() { var b := forall c: SomeClass :: c != null ==> c.f == 0; // error: non-ghost code requires bounds @@ -192,3 +198,4 @@ module DependencyOnAllAllocatedObjects { var f: int; } } + diff --git a/Test/dafny0/NonGhostQuantifiers.dfy.expect b/Test/dafny0/NonGhostQuantifiers.dfy.expect index 1e2fce17..6b737add 100644 --- a/Test/dafny0/NonGhostQuantifiers.dfy.expect +++ b/Test/dafny0/NonGhostQuantifiers.dfy.expect @@ -6,16 +6,16 @@ NonGhostQuantifiers.dfy(167,4): Error: a quantifier involved in a function defin NonGhostQuantifiers.dfy(171,4): Error: a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'c' NonGhostQuantifiers.dfy(176,4): Error: a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'c' NonGhostQuantifiers.dfy(181,4): Error: a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'c' -NonGhostQuantifiers.dfy(186,13): Error: 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 'c' -NonGhostQuantifiers.dfy(16,5): Error: 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 'n' -NonGhostQuantifiers.dfy(45,4): Error: 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 'n' -NonGhostQuantifiers.dfy(49,4): Error: 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 'd' -NonGhostQuantifiers.dfy(53,4): Error: 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 'n' -NonGhostQuantifiers.dfy(77,5): Error: 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 'i' -NonGhostQuantifiers.dfy(81,5): Error: 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 'j' -NonGhostQuantifiers.dfy(91,5): Error: 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 'j' -NonGhostQuantifiers.dfy(106,5): Error: 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 'j' -NonGhostQuantifiers.dfy(114,10): Error: 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 'y' -NonGhostQuantifiers.dfy(123,8): Error: 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 'x' +NonGhostQuantifiers.dfy(192,13): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'c' +NonGhostQuantifiers.dfy(16,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'n' +NonGhostQuantifiers.dfy(45,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'n' +NonGhostQuantifiers.dfy(49,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'd' +NonGhostQuantifiers.dfy(53,4): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'n' +NonGhostQuantifiers.dfy(77,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' +NonGhostQuantifiers.dfy(81,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'j' +NonGhostQuantifiers.dfy(91,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'j' +NonGhostQuantifiers.dfy(106,5): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'j' +NonGhostQuantifiers.dfy(114,10): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'y' +NonGhostQuantifiers.dfy(123,8): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'x' NonGhostQuantifiers.dfy(140,8): Error: 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) 20 resolution/type errors detected in NonGhostQuantifiers.dfy diff --git a/Test/dafny0/ParallelResolveErrors.dfy b/Test/dafny0/ParallelResolveErrors.dfy index 61956651..8c48487d 100644 --- a/Test/dafny0/ParallelResolveErrors.dfy +++ b/Test/dafny0/ParallelResolveErrors.dfy @@ -7,7 +7,6 @@ class C { ghost method Init_ModifyNothing() { } ghost method Init_ModifyThis() modifies this; { - data := 6; // error: assignment to a non-ghost field gdata := 7; } ghost method Init_ModifyStuff(c: C) modifies this, c; { } @@ -120,3 +119,15 @@ method M3(c: C) c.GhostMethodWithModifies(x); // error: not allowed to call method with nonempty modifies clause } } + +module AnotherModule { + class C { + var data: int; + ghost var gdata: int; + ghost method Init_ModifyThis() modifies this; + { + data := 6; // error: assignment to a non-ghost field + gdata := 7; + } + } +} diff --git a/Test/dafny0/ParallelResolveErrors.dfy.expect b/Test/dafny0/ParallelResolveErrors.dfy.expect index 00030994..4d25ba11 100644 --- a/Test/dafny0/ParallelResolveErrors.dfy.expect +++ b/Test/dafny0/ParallelResolveErrors.dfy.expect @@ -1,23 +1,23 @@ -ParallelResolveErrors.dfy(10,9): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ParallelResolveErrors.dfy(21,4): Error: LHS of assignment must denote a mutable variable -ParallelResolveErrors.dfy(26,6): Error: body of forall statement is attempting to update a variable declared outside the forall statement +ParallelResolveErrors.dfy(129,11): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ParallelResolveErrors.dfy(20,4): Error: LHS of assignment must denote a mutable variable +ParallelResolveErrors.dfy(25,6): Error: body of forall statement is attempting to update a variable declared outside the forall statement +ParallelResolveErrors.dfy(42,6): Error: body of forall statement is attempting to update a variable declared outside the forall statement ParallelResolveErrors.dfy(43,6): Error: body of forall statement is attempting to update a variable declared outside the forall statement -ParallelResolveErrors.dfy(44,6): Error: body of forall statement is attempting to update a variable declared outside the forall statement -ParallelResolveErrors.dfy(56,13): Error: new allocation not supported in forall statements +ParallelResolveErrors.dfy(55,13): Error: new allocation not supported in forall statements +ParallelResolveErrors.dfy(60,13): Error: new allocation not allowed in ghost context ParallelResolveErrors.dfy(61,13): Error: new allocation not allowed in ghost context ParallelResolveErrors.dfy(62,13): Error: new allocation not allowed in ghost context ParallelResolveErrors.dfy(63,13): Error: new allocation not allowed in ghost context -ParallelResolveErrors.dfy(64,13): Error: new allocation not allowed in ghost context -ParallelResolveErrors.dfy(65,22): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause -ParallelResolveErrors.dfy(66,20): Error: the body of the enclosing forall statement is not allowed to call non-ghost methods -ParallelResolveErrors.dfy(73,19): Error: trying to break out of more loop levels than there are enclosing loops -ParallelResolveErrors.dfy(77,18): Error: return statement is not allowed inside a forall statement -ParallelResolveErrors.dfy(84,21): Error: trying to break out of more loop levels than there are enclosing loops -ParallelResolveErrors.dfy(85,20): Error: trying to break out of more loop levels than there are enclosing loops -ParallelResolveErrors.dfy(86,20): Error: break label is undefined or not in scope: OutsideLoop -ParallelResolveErrors.dfy(95,24): Error: trying to break out of more loop levels than there are enclosing loops -ParallelResolveErrors.dfy(96,24): Error: break label is undefined or not in scope: OutsideLoop -ParallelResolveErrors.dfy(107,9): Error: the body of the enclosing forall statement is not allowed to update heap locations -ParallelResolveErrors.dfy(115,29): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause -ParallelResolveErrors.dfy(120,29): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause +ParallelResolveErrors.dfy(64,22): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause +ParallelResolveErrors.dfy(65,20): Error: the body of the enclosing forall statement is not allowed to call non-ghost methods +ParallelResolveErrors.dfy(72,19): Error: trying to break out of more loop levels than there are enclosing loops +ParallelResolveErrors.dfy(76,18): Error: return statement is not allowed inside a forall statement +ParallelResolveErrors.dfy(83,21): Error: trying to break out of more loop levels than there are enclosing loops +ParallelResolveErrors.dfy(84,20): Error: trying to break out of more loop levels than there are enclosing loops +ParallelResolveErrors.dfy(85,20): Error: break label is undefined or not in scope: OutsideLoop +ParallelResolveErrors.dfy(94,24): Error: trying to break out of more loop levels than there are enclosing loops +ParallelResolveErrors.dfy(95,24): Error: break label is undefined or not in scope: OutsideLoop +ParallelResolveErrors.dfy(106,9): Error: the body of the enclosing forall statement is not allowed to update heap locations +ParallelResolveErrors.dfy(114,29): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause +ParallelResolveErrors.dfy(119,29): Error: the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause 22 resolution/type errors detected in ParallelResolveErrors.dfy diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 2fab6bf3..d3514b2b 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -102,7 +102,7 @@ class EE { } // --------------- ghost tests ------------------------------------- - +module HereAreMoreGhostTests { datatype GhostDt = Nil(ghost extraInfo: int) | Cons(data: int, tail: GhostDt, ghost moreInfo: int) @@ -154,7 +154,7 @@ class GhostTests { ensures false; { while (true) - decreases *; // error: not allowed in ghost context +//KRML-confirmed decreases *; // error: not allowed in ghost context { } } @@ -228,7 +228,7 @@ class GhostTests { if (p == 67) { break break; // fine, since this is not a ghost context } else if (*) { - break break break; // error: tries to break out of more loop levels than there are +//KRML-confirmed break break break; // error: tries to break out of more loop levels than there are } q := q + 1; } @@ -238,7 +238,7 @@ class GhostTests { p := p + 1; } } -method BreakMayNotBeFineHere_Ghost(ghost t: int) + method BreakMayNotBeFineHere_Ghost(ghost t: int) { var n := 0; ghost var k := 0; @@ -297,7 +297,7 @@ method BreakMayNotBeFineHere_Ghost(ghost t: int) } } } - +} //HereAreMoreGhostTests method DuplicateLabels(n: int) { var x; if (n < 7) { @@ -364,17 +364,17 @@ method DatatypeDestructors(d: DTD_List) { } } method DatatypeDestructors_Ghost(d: DTD_List) { - var g1 := d.g; // error: cannot use ghost member in non-ghost code + var g1 := d.g; // error: cannot use ghost member in non-ghost code//KRML-confirmed } // ------------------- print statements --------------------------------------- - +module GhostPrintAttempts { method PrintOnlyNonGhosts(a: int, ghost b: int) { print "a: ", a, "\n"; print "b: ", b, "\n"; // error: print statement cannot take ghosts } - +} // ------------------- auto-added type arguments ------------------------------ class GenericClass { var data: T; } @@ -439,11 +439,11 @@ method TestCalc_Ghost(m: int, n: int, a: bool, b: bool) { calc { n + m; - { print n + m; } // error: non-ghost statements are not allowed in hints + { print n + m; } // error: non-ghost statements are not allowed in hints//KRML-confirmed m + n; } } - +module MyOwnModule { class SideEffectChecks { ghost var ycalc: int; @@ -461,11 +461,11 @@ class SideEffectChecks { var x: int; calc { 0; - { Mod(0); } // methods with side-effects are not allowed + { Mod(0); } // error: methods with side-effects are not allowed ycalc; - { ycalc := 1; } // heap updates are not allowed + { ycalc := 1; } // error: heap updates are not allowed 1; - { x := 1; } // updates to locals defined outside of the hint are not allowed + { x := 1; } // error: updates to locals defined outside of the hint are not allowed x; { var x: int; @@ -475,7 +475,7 @@ class SideEffectChecks { } } } - +} // ------------------- nameless constructors ------------------------------ class YHWH { @@ -523,13 +523,13 @@ method AssignSuchThatFromGhost() var x: int; ghost var g: int; - x := g; // error: ghost cannot flow into non-ghost + x := g; // error: ghost cannot flow into non-ghost//KRML-confirmed x := *; assume x == g; // this mix of ghosts and non-ghosts is cool (but, of course, // the compiler will complain) - x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well + x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well//KRML-confirmed x :| assume x == g; // this is cool, since it's an assume (but, of course, the // compiler will complain) @@ -605,7 +605,7 @@ method LetSuchThat(ghost z: int, n: nat) } method LetSuchThat_Ghost(ghost z: int, n: nat) { - var x := var y :| y < z; y; // error: contraint depend on ghost (z) + var x := var y :| y < z; y; // error: contraint depend on ghost (z)//KRML-confirmed } // ------------ quantified variables whose types are not inferred ---------- @@ -677,9 +677,9 @@ module GhostAllocationTests { 5; { var y := new G; } // error: 'new' not allowed in ghost contexts 2 + 3; - { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context + { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context//KRML-confirmed 1 + 4; - { GhostNew5(g); } // error: cannot call method with nonempty modifies + { GhostNew5(g); } // error: cannot call method with nonempty modifies//KRML-confirmed -5 + 10; } } @@ -735,7 +735,7 @@ module StatementsInExpressions { { calc { 5; - { SideEffect(); } // error: cannot call method with side effects + { SideEffect(); } // error: cannot call method with side effects//KRML 5; } } @@ -745,7 +745,7 @@ module StatementsInExpressions { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method + { NonGhostMethod(); } // error: cannot call non-ghost method//KRML-confirmed { var x := 8; while x != 0 decreases *; // error: cannot use 'decreases *' in a ghost context @@ -759,12 +759,12 @@ module StatementsInExpressions { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field - { MyGhostField := 12; } // error: cannot assign to any field - { SideEffect(); } // error: cannot call (ghost) method with a modifies clause + { MyField := 12; } // error: cannot assign to a field//KRML-confirmed + { MyGhostField := 12; } // error: cannot assign to any field//KRML-confirmed + { SideEffect(); } // error: cannot call (ghost) method with a modifies clause//KRML-confirmed { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop + modifies this; // error: cannot use a modifies clause on a loop//KRML-confirmed { x := x - 1; } @@ -783,7 +783,7 @@ module StatementsInExpressions { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method + { NonGhostMethod(); } // error: cannot call non-ghost method//KRML-confirmed { var x := 8; while x != 0 decreases *; // error: cannot use 'decreases *' in a ghost context @@ -791,12 +791,12 @@ module StatementsInExpressions { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field - { MyGhostField := 12; } // error: cannot assign to any field - { M(); } // error: cannot call (ghost) method with a modifies clause + { MyField := 12; } // error: cannot assign to a field//KRML-confirmed + { MyGhostField := 12; } // error: cannot assign to any field//KRML-confirmed + { M(); } // error: cannot call (ghost) method with a modifies clause//KRML-confirmed { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop + modifies this; // error: cannot use a modifies clause on a loop//KRML-confirmed { x := x - 1; } @@ -822,7 +822,7 @@ module StatementsInExpressions { { MyLemma(); MyGhostMethod(); // error: modifi2es state - OrdinaryMethod(); // error: not a ghost + OrdinaryMethod(); // error: not a ghost//KRML-confirmed OutParamMethod(); // error: has out-parameters 10 } @@ -1446,3 +1446,219 @@ module SuchThat { w } } + +// ---------------------- NEW STUFF ---------------------------------------- + +module GhostTests { + class G { } + + method GhostNew4(n: nat) + { + var g := new G; + calc { + 5; + 2 + 3; + { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context//ADD:680 + 1 + 4; + { GhostNew5(g); } // error: cannot call method with nonempty modifies//ADD:682 + -5 + 10; + } + } + + ghost method GhostNew5(g: G) + modifies g; + { + } + + class MyClass { + ghost method SideEffect() + modifies this; + { + } + + method NonGhostMethod() + { + } + + ghost method M() + modifies this; + { + calc { + 5; + { SideEffect(); } // error: cannot call method with side effects//ADD:738 + 5; + } + } + function F(): int + { + calc { + 6; + { assert 6 < 8; } + { NonGhostMethod(); } // error: cannot call non-ghost method//ADD:748 + { var x := 8; + while x != 0 + { + x := x - 1; + } + } + { var x := 8; + while x != 0 + { + x := x - 1; + } + } + { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field//ADD:762 + { MyGhostField := 12; } // error: cannot assign to any field//ADD:763 + { SideEffect(); } // error: cannot call (ghost) method with a modifies clause//ADD:764 + { var x := 8; + while x != 0 + modifies this; // error: cannot use a modifies clause on a loop//ADD:767 + { + x := x - 1; + } + } + 6; + } + 5 + } + var MyField: int; + ghost var MyGhostField: int; + method N() + { + var y := + calc { + 6; + { assert 6 < 8; } + { NonGhostMethod(); } // error: cannot call non-ghost method//ADD:786 + { var x := 8; + while x != 0 + { + x := x - 1; + } + } + { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field//ADD:794 + { MyGhostField := 12; } // error: cannot assign to any field//ADD:795 + { M(); } // error: cannot call (ghost) method with a modifies clause//ADD:796 + { var x := 8; + while x != 0 + modifies this; // error: cannot use a modifies clause on a loop//ADD:799 + { + x := x - 1; + } + } + { var x := 8; + while x != 0 + { + x := x - 1; + } + } + 6; + } + 5; + } + ghost method MyLemma() + ghost method MyGhostMethod() + modifies this; + method OrdinaryMethod() + ghost method OutParamMethod() returns (y: int) + + function UseLemma(): int + { + MyLemma(); + OrdinaryMethod(); // error: not a ghost//ADD:825 + 10 + } + } +} + +module EvenMoreGhostTests { + ghost method NiceTry() + ensures false; + { + while (true) + decreases *; // error: not allowed in ghost context//ADD:157 + { + } + } + method BreakMayNotBeFineHere() + { + var n := 0; + var p := 0; + while (true) + { + var dontKnow; + if (n == 112) { + } else if (dontKnow == 708) { + while * { + label IfNest: + if (p == 67) { + break break; // fine, since this is not a ghost context + } else if (*) { + break break break; // error: tries to break out of more loop levels than there are//ADD:231 + } + } + } + } + } + ghost method Bad() + { + var x: int; + calc { + 1; +//****** { x := 1; } // error: updates to locals defined outside of the hint are not allowed + x; + { + var x: int; + x := 1; // this is OK + } + 1; + } + } +} + +module BadGhostTransfer { + datatype DTD_List = DTD_Nil | DTD_Cons(Car: int, Cdr: DTD_List, ghost g: int) + + method DatatypeDestructors_Ghost(d: DTD_List) { + var g1 := d.g; // error: cannot use ghost member in non-ghost code//ADD:367 + } + method AssignSuchThatFromGhost() + { + var x: int; + ghost var g: int; + + x := g; // error: ghost cannot flow into non-ghost//ADD:526 + + x := *; + assume x == g; // this mix of ghosts and non-ghosts is cool (but, of course, + // the compiler will complain) + + x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well//ADD:532 + + x :| assume x == g; // this is cool, since it's an assume (but, of course, the + // compiler will complain) + + x :| x == 5; + g :| g <= g; + g :| assume g < g; // the compiler will complain here, despite the LHS being + // ghost -- and rightly so, since an assume is used + } +} + +module MoreGhostPrintAttempts { + method TestCalc_Ghost(m: int, n: int, a: bool, b: bool) + { + calc { + n + m; + { print n + m; } // error: non-ghost statements are not allowed in hints//ADD:442 + m + n; + } + } +} + +module MoreLetSuchThatExpr { + method LetSuchThat_Ghost(ghost z: int, n: nat) + { + var x := var y :| y < z; y; // error: contraint depend on ghost (z)//ADD:608 + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index 0286778b..ee2dd5f7 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -1,3 +1,21 @@ +ResolutionErrors.dfy(113,9): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(114,9): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(118,11): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(119,10): Error: actual out-parameter 0 is required to be a ghost variable +ResolutionErrors.dfy(126,15): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(130,23): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(137,4): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(141,21): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(142,35): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(151,10): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(251,27): Error: ghost-context break statement is not allowed to break out of non-ghost structure +ResolutionErrors.dfy(274,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(288,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(293,8): Error: return statement is not allowed in this context (because it is guarded by a specification-only expression) +ResolutionErrors.dfy(375,15): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(464,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(466,14): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(468,10): Error: a hint is not allowed to update a variable declared outside the hint ResolutionErrors.dfy(558,7): Error: RHS (of type List) not assignable to LHS (of type List) ResolutionErrors.dfy(563,7): Error: RHS (of type List) not assignable to LHS (of type List) ResolutionErrors.dfy(577,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) @@ -13,26 +31,11 @@ ResolutionErrors.dfy(652,11): Error: the body of the enclosing forall statement ResolutionErrors.dfy(652,14): Error: new allocation not allowed in ghost context ResolutionErrors.dfy(662,23): Error: 'new' is not allowed in ghost contexts ResolutionErrors.dfy(669,15): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(669,15): Error: only ghost methods can be called from this context ResolutionErrors.dfy(678,17): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(680,29): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(682,17): Error: calls to methods with side-effects are not allowed inside a hint ResolutionErrors.dfy(700,21): Error: the type of this variable is underspecified -ResolutionErrors.dfy(738,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(748,24): Error: only ghost methods can be called from this context ResolutionErrors.dfy(751,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(762,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(763,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(764,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(767,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(786,24): Error: only ghost methods can be called from this context ResolutionErrors.dfy(789,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(794,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(795,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(796,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(799,21): Error: a while statement used inside a hint is not allowed to have a modifies clause ResolutionErrors.dfy(824,19): Error: calls to methods with side-effects are not allowed inside a statement expression -ResolutionErrors.dfy(825,20): Error: only ghost methods can be called from this context ResolutionErrors.dfy(826,20): Error: wrong number of method result arguments (got 0, expected 1) ResolutionErrors.dfy(838,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') ResolutionErrors.dfy(848,4): Error: ghost variables are allowed only in specification contexts @@ -74,8 +77,8 @@ ResolutionErrors.dfy(1146,6): Error: RHS (of type P) not assignable to LHS ResolutionErrors.dfy(1151,13): Error: arguments must have the same type (got P and P) ResolutionErrors.dfy(1152,13): Error: arguments must have the same type (got P and P) ResolutionErrors.dfy(1153,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1176,38): Error: 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 'o' -ResolutionErrors.dfy(1178,24): Error: 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 'o' +ResolutionErrors.dfy(1176,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1178,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' ResolutionErrors.dfy(1283,26): Error: the type of this variable is underspecified ResolutionErrors.dfy(1284,31): Error: the type of this variable is underspecified ResolutionErrors.dfy(1285,29): Error: the type of this variable is underspecified @@ -106,6 +109,29 @@ ResolutionErrors.dfy(1440,11): Error: type of RHS of assign-such-that statement ResolutionErrors.dfy(1441,9): Error: type of RHS of assign-such-that statement must be boolean (got int) ResolutionErrors.dfy(1442,13): Error: type of RHS of assign-such-that statement must be boolean (got int) ResolutionErrors.dfy(1445,15): Error: type of RHS of let-such-that expression must be boolean (got int) +ResolutionErrors.dfy(1488,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1510,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1511,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1512,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1515,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1497,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1510,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1539,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1540,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1541,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1544,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1532,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1539,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1568,20): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1461,29): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1463,17): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1579,16): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1597,12): Error: trying to break out of more loop levels than there are enclosing loops +ResolutionErrors.dfy(1623,16): Error: ghost fields are allowed only in specification contexts +ResolutionErrors.dfy(1630,9): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1636,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(1653,8): Error: 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) +ResolutionErrors.dfy(1662,26): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(488,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -113,25 +139,6 @@ ResolutionErrors.dfy(92,14): Error: the name 'David' denotes a datatype construc ResolutionErrors.dfy(93,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(95,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(97,18): Error: wrong number of arguments to datatype constructor David (found 2, expected 1) -ResolutionErrors.dfy(113,9): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(114,9): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(118,11): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(119,10): Error: actual out-parameter 0 is required to be a ghost variable -ResolutionErrors.dfy(126,15): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(130,23): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(137,4): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(141,21): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(142,35): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(151,10): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(157,16): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(231,12): Error: trying to break out of more loop levels than there are enclosing loops -ResolutionErrors.dfy(251,27): Error: ghost-context break statement is not allowed to break out of non-ghost structure -ResolutionErrors.dfy(274,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop -ResolutionErrors.dfy(288,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop -ResolutionErrors.dfy(293,8): Error: return statement is not allowed in this context (because it is guarded by a specification-only expression) -ResolutionErrors.dfy(464,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(466,14): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(468,10): Error: a hint is not allowed to update a variable declared outside the hint ResolutionErrors.dfy(494,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called ResolutionErrors.dfy(499,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called ResolutionErrors.dfy(500,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called @@ -168,8 +175,6 @@ ResolutionErrors.dfy(345,9): Error: a constructor is allowed to be called only w ResolutionErrors.dfy(359,16): Error: arguments must have the same type (got int and DTD_List) ResolutionErrors.dfy(360,16): Error: arguments must have the same type (got DTD_List and int) ResolutionErrors.dfy(361,25): Error: arguments must have the same type (got bool and int) -ResolutionErrors.dfy(367,14): Error: ghost fields are allowed only in specification contexts -ResolutionErrors.dfy(375,15): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(400,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) ResolutionErrors.dfy(412,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) ResolutionErrors.dfy(420,6): Error: arguments to + must be of a numeric type or a collection type (instead got bool) @@ -180,11 +185,7 @@ ResolutionErrors.dfy(429,10): Error: first argument to ==> must be of type bool ResolutionErrors.dfy(429,10): Error: second argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(434,10): Error: first argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(434,10): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(442,6): Error: 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) -ResolutionErrors.dfy(526,7): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(532,2): Error: non-ghost variable cannot be assigned a value that depends on a ghost ResolutionErrors.dfy(603,18): Error: unresolved identifier: w -ResolutionErrors.dfy(608,24): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(714,11): Error: lemmas are not allowed to have modifies clauses ResolutionErrors.dfy(976,9): Error: unresolved identifier: s ResolutionErrors.dfy(987,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) @@ -198,4 +199,4 @@ ResolutionErrors.dfy(1164,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1185,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1192,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1207,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -200 resolution/type errors detected in ResolutionErrors.dfy +201 resolution/type errors detected in ResolutionErrors.dfy diff --git a/Test/dafny0/TypeTests.dfy b/Test/dafny0/TypeTests.dfy index b44f4d68..a9d473f6 100644 --- a/Test/dafny0/TypeTests.dfy +++ b/Test/dafny0/TypeTests.dfy @@ -39,7 +39,7 @@ datatype ReverseOrder_TheCounterpart = // --------------------- -class ArrayTests { +module ArrayTests { ghost method G(a: array) requires a != null && 10 <= a.Length; modifies a; @@ -167,31 +167,33 @@ module Expl_Module { // --------------------- more ghost tests, for assign-such-that statements -method M() -{ - ghost var b: bool; - ghost var k: int, l: int; - var m: int; - - k :| k < 10; - k, m :| 0 <= k < m; // error: LHS has non-ghost and RHS has ghost - m :| m < 10; - - // Because of the ghost guard, these 'if' statements are ghost contexts, so only - // assignments to ghosts are allowed. - if (b) { - k :| k < 10; // should be allowed - k, l :| 0 <= k < l; // ditto - } - if (b) { - m :| m < 10; // error: not allowed in ghost context - k, m :| 0 <= k < m; // error: not allowed in ghost context +module MoreGhostTests { + method M() + { + ghost var b: bool; + ghost var k: int, l: int; + var m: int; + + k :| k < 10; + k, m :| 0 <= k < m; // error: LHS has non-ghost and RHS has ghost + m :| m < 10; + + // Because of the ghost guard, these 'if' statements are ghost contexts, so only + // assignments to ghosts are allowed. + if (b) { + k :| k < 10; // should be allowed + k, l :| 0 <= k < l; // ditto + } + if (b) { + m :| m < 10; // error: not allowed in ghost context + k, m :| 0 <= k < m; // error: not allowed in ghost context + } } -} -ghost method GhostM() returns (x: int) -{ - x :| true; // no problem (but there once was a problem with this case, where an error was generated for no reason) + ghost method GhostM() returns (x: int) + { + x :| true; // no problem (but there once was a problem with this case, where an error was generated for no reason) + } } // ------------------ cycles that could arise from proxy assignments --------- diff --git a/Test/dafny0/TypeTests.dfy.expect b/Test/dafny0/TypeTests.dfy.expect index 8206fd43..de0bfbed 100644 --- a/Test/dafny0/TypeTests.dfy.expect +++ b/Test/dafny0/TypeTests.dfy.expect @@ -1,6 +1,10 @@ -TypeTests.dfy(205,15): Error: incorrect type of datatype constructor argument (found ? -> ?, expected ? -> Dt) -TypeTests.dfy(211,15): Error: incorrect type of datatype constructor argument (found ? -> ?, expected ? -> Dt) -TypeTests.dfy(218,6): Error: RHS (of type set) not assignable to LHS (of type ?) +TypeTests.dfy(47,9): Error: 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) +TypeTests.dfy(178,7): Error: non-ghost variable cannot be assigned a value that depends on a ghost +TypeTests.dfy(188,6): Error: cannot assign to non-ghost variable in a ghost context +TypeTests.dfy(189,9): Error: cannot assign to non-ghost variable in a ghost context +TypeTests.dfy(207,15): Error: incorrect type of datatype constructor argument (found ? -> ?, expected ? -> Dt) +TypeTests.dfy(213,15): Error: incorrect type of datatype constructor argument (found ? -> ?, expected ? -> Dt) +TypeTests.dfy(220,6): Error: RHS (of type set) not assignable to LHS (of type ?) TypeTests.dfy(7,17): Error: type mismatch for argument 0 (function expects C, got D) TypeTests.dfy(7,20): Error: type mismatch for argument 1 (function expects D, got C) TypeTests.dfy(8,15): Error: type mismatch for argument 0 (function expects C, got int) @@ -8,7 +12,6 @@ TypeTests.dfy(8,18): Error: type mismatch for argument 1 (function expects D, go TypeTests.dfy(14,16): Error: incorrect type of method in-parameter 0 (expected int, got bool) TypeTests.dfy(15,12): Error: incorrect type of method out-parameter 0 (expected int, got C) TypeTests.dfy(15,12): Error: incorrect type of method out-parameter 1 (expected C, got int) -TypeTests.dfy(47,9): Error: 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) TypeTests.dfy(56,6): Error: Duplicate local-variable name: z TypeTests.dfy(58,6): Error: Duplicate local-variable name: x TypeTests.dfy(61,8): Error: Duplicate local-variable name: x @@ -56,8 +59,5 @@ TypeTests.dfy(151,13): Error: sorry, cannot instantiate type parameter with a su TypeTests.dfy(152,2): Error: sorry, cannot instantiate type parameter with a subrange type TypeTests.dfy(153,16): Error: sorry, cannot instantiate type parameter with a subrange type TypeTests.dfy(154,14): Error: sorry, cannot instantiate type parameter with a subrange type -TypeTests.dfy(177,5): Error: non-ghost variable cannot be assigned a value that depends on a ghost -TypeTests.dfy(187,4): Error: cannot assign to non-ghost variable in a ghost context -TypeTests.dfy(188,7): Error: cannot assign to non-ghost variable in a ghost context TypeTests.dfy(21,9): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'NeverendingList' can be constructed 62 resolution/type errors detected in TypeTests.dfy diff --git a/Test/dafny4/set-compr.dfy.expect b/Test/dafny4/set-compr.dfy.expect index b31c6ac0..615ee2bc 100644 --- a/Test/dafny4/set-compr.dfy.expect +++ b/Test/dafny4/set-compr.dfy.expect @@ -1,3 +1,3 @@ -set-compr.dfy(25,7): Error: 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 'o' -set-compr.dfy(51,13): Error: 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 'o' +set-compr.dfy(25,7): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +set-compr.dfy(51,13): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' 2 resolution/type errors detected in set-compr.dfy -- cgit v1.2.3 From 4c21d765625b35eab9f5dc4ca21f170d3f7a2f04 Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 28 Sep 2015 13:27:22 -0700 Subject: Whitespace changes in test file --- Test/dafny0/ResolutionErrors.dfy | 150 +++++--------- Test/dafny0/ResolutionErrors.dfy.expect | 344 ++++++++++++++++---------------- 2 files changed, 221 insertions(+), 273 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index d3514b2b..a4161a46 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -150,14 +150,6 @@ class GhostTests { r := r + g; // fine, for the same reason r := N(20, 20); // error: call to non-ghost method from ghost method is not okay } - ghost method NiceTry() - ensures false; - { - while (true) -//KRML-confirmed decreases *; // error: not allowed in ghost context - { - } - } ghost method BreaksAreFineHere(t: int) { var n := 0; @@ -227,8 +219,6 @@ class GhostTests { label IfNest: if (p == 67) { break break; // fine, since this is not a ghost context - } else if (*) { -//KRML-confirmed break break break; // error: tries to break out of more loop levels than there are } q := q + 1; } @@ -363,9 +353,6 @@ method DatatypeDestructors(d: DTD_List) { ghost var g0 := d.g; // fine } } -method DatatypeDestructors_Ghost(d: DTD_List) { - var g1 := d.g; // error: cannot use ghost member in non-ghost code//KRML-confirmed -} // ------------------- print statements --------------------------------------- module GhostPrintAttempts { @@ -435,47 +422,41 @@ method TestCalc(m: int, n: int, a: bool, b: bool) ==> n + m + 2; // error: ==> operator requires boolean lines } } -method TestCalc_Ghost(m: int, n: int, a: bool, b: bool) -{ - calc { - n + m; - { print n + m; } // error: non-ghost statements are not allowed in hints//KRML-confirmed - m + n; - } -} + module MyOwnModule { -class SideEffectChecks { - ghost var ycalc: int; + class SideEffectChecks { + ghost var ycalc: int; - ghost method Mod(a: int) - modifies this; - ensures ycalc == a; - { - ycalc := a; - } + ghost method Mod(a: int) + modifies this; + ensures ycalc == a; + { + ycalc := a; + } - ghost method Bad() - modifies this; - ensures 0 == 1; - { - var x: int; - calc { - 0; - { Mod(0); } // error: methods with side-effects are not allowed - ycalc; - { ycalc := 1; } // error: heap updates are not allowed - 1; - { x := 1; } // error: updates to locals defined outside of the hint are not allowed - x; - { - var x: int; - x := 1; // this is OK + ghost method Bad() + modifies this; + ensures 0 == 1; + { + var x: int; + calc { + 0; + { Mod(0); } // error: methods with side-effects are not allowed + ycalc; + { ycalc := 1; } // error: heap updates are not allowed + 1; + { x := 1; } // error: updates to locals defined outside of the hint are not allowed + x; + { + var x: int; + x := 1; // this is OK + } + 1; } - 1; } } } -} + // ------------------- nameless constructors ------------------------------ class YHWH { @@ -523,14 +504,10 @@ method AssignSuchThatFromGhost() var x: int; ghost var g: int; - x := g; // error: ghost cannot flow into non-ghost//KRML-confirmed - x := *; assume x == g; // this mix of ghosts and non-ghosts is cool (but, of course, // the compiler will complain) - x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well//KRML-confirmed - x :| assume x == g; // this is cool, since it's an assume (but, of course, the // compiler will complain) @@ -603,10 +580,6 @@ method LetSuchThat(ghost z: int, n: nat) x := var w := 2*w; w; // error: the 'w' in the RHS of the assignment is not in scope ghost var xg := var w :| w == 2*w; w; } -method LetSuchThat_Ghost(ghost z: int, n: nat) -{ - var x := var y :| y < z; y; // error: contraint depend on ghost (z)//KRML-confirmed -} // ------------ quantified variables whose types are not inferred ---------- @@ -677,10 +650,6 @@ module GhostAllocationTests { 5; { var y := new G; } // error: 'new' not allowed in ghost contexts 2 + 3; - { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context//KRML-confirmed - 1 + 4; - { GhostNew5(g); } // error: cannot call method with nonempty modifies//KRML-confirmed - -5 + 10; } } @@ -730,22 +699,11 @@ module StatementsInExpressions { { } - ghost method M() - modifies this; - { - calc { - 5; - { SideEffect(); } // error: cannot call method with side effects//KRML - 5; - } - } - function F(): int { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method//KRML-confirmed { var x := 8; while x != 0 decreases *; // error: cannot use 'decreases *' in a ghost context @@ -759,12 +717,8 @@ module StatementsInExpressions { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field//KRML-confirmed - { MyGhostField := 12; } // error: cannot assign to any field//KRML-confirmed - { SideEffect(); } // error: cannot call (ghost) method with a modifies clause//KRML-confirmed { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop//KRML-confirmed { x := x - 1; } @@ -783,7 +737,6 @@ module StatementsInExpressions { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method//KRML-confirmed { var x := 8; while x != 0 decreases *; // error: cannot use 'decreases *' in a ghost context @@ -791,12 +744,8 @@ module StatementsInExpressions { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field//KRML-confirmed - { MyGhostField := 12; } // error: cannot assign to any field//KRML-confirmed - { M(); } // error: cannot call (ghost) method with a modifies clause//KRML-confirmed { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop//KRML-confirmed { x := x - 1; } @@ -822,7 +771,6 @@ module StatementsInExpressions { { MyLemma(); MyGhostMethod(); // error: modifi2es state - OrdinaryMethod(); // error: not a ghost//KRML-confirmed OutParamMethod(); // error: has out-parameters 10 } @@ -1458,9 +1406,9 @@ module GhostTests { calc { 5; 2 + 3; - { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context//ADD:680 + { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context 1 + 4; - { GhostNew5(g); } // error: cannot call method with nonempty modifies//ADD:682 + { GhostNew5(g); } // error: cannot call method with nonempty modifies -5 + 10; } } @@ -1485,7 +1433,7 @@ module GhostTests { { calc { 5; - { SideEffect(); } // error: cannot call method with side effects//ADD:738 + { SideEffect(); } // error: cannot call method with side effects 5; } } @@ -1494,7 +1442,7 @@ module GhostTests { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method//ADD:748 + { NonGhostMethod(); } // error: cannot call non-ghost method { var x := 8; while x != 0 { @@ -1507,12 +1455,12 @@ module GhostTests { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field//ADD:762 - { MyGhostField := 12; } // error: cannot assign to any field//ADD:763 - { SideEffect(); } // error: cannot call (ghost) method with a modifies clause//ADD:764 + { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field + { MyGhostField := 12; } // error: cannot assign to any field + { SideEffect(); } // error: cannot call (ghost) method with a modifies clause { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop//ADD:767 + modifies this; // error: cannot use a modifies clause on a loop { x := x - 1; } @@ -1529,19 +1477,19 @@ module GhostTests { calc { 6; { assert 6 < 8; } - { NonGhostMethod(); } // error: cannot call non-ghost method//ADD:786 + { NonGhostMethod(); } // error: cannot call non-ghost method { var x := 8; while x != 0 { x := x - 1; } } - { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field//ADD:794 - { MyGhostField := 12; } // error: cannot assign to any field//ADD:795 - { M(); } // error: cannot call (ghost) method with a modifies clause//ADD:796 + { MyField := 12; } // error: cannot assign to a field, and especially not a non-ghost field + { MyGhostField := 12; } // error: cannot assign to any field + { M(); } // error: cannot call (ghost) method with a modifies clause { var x := 8; while x != 0 - modifies this; // error: cannot use a modifies clause on a loop//ADD:799 + modifies this; // error: cannot use a modifies clause on a loop { x := x - 1; } @@ -1565,7 +1513,7 @@ module GhostTests { function UseLemma(): int { MyLemma(); - OrdinaryMethod(); // error: not a ghost//ADD:825 + OrdinaryMethod(); // error: not a ghost 10 } } @@ -1576,7 +1524,7 @@ module EvenMoreGhostTests { ensures false; { while (true) - decreases *; // error: not allowed in ghost context//ADD:157 + decreases *; // error: not allowed in ghost context { } } @@ -1594,7 +1542,7 @@ module EvenMoreGhostTests { if (p == 67) { break break; // fine, since this is not a ghost context } else if (*) { - break break break; // error: tries to break out of more loop levels than there are//ADD:231 + break break break; // error: tries to break out of more loop levels than there are } } } @@ -1620,20 +1568,20 @@ module BadGhostTransfer { datatype DTD_List = DTD_Nil | DTD_Cons(Car: int, Cdr: DTD_List, ghost g: int) method DatatypeDestructors_Ghost(d: DTD_List) { - var g1 := d.g; // error: cannot use ghost member in non-ghost code//ADD:367 + var g1 := d.g; // error: cannot use ghost member in non-ghost code } method AssignSuchThatFromGhost() { var x: int; ghost var g: int; - x := g; // error: ghost cannot flow into non-ghost//ADD:526 + x := g; // error: ghost cannot flow into non-ghost x := *; assume x == g; // this mix of ghosts and non-ghosts is cool (but, of course, // the compiler will complain) - x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well//ADD:532 + x :| x == g; // error: left-side has non-ghost, so RHS must be non-ghost as well x :| assume x == g; // this is cool, since it's an assume (but, of course, the // compiler will complain) @@ -1650,7 +1598,7 @@ module MoreGhostPrintAttempts { { calc { n + m; - { print n + m; } // error: non-ghost statements are not allowed in hints//ADD:442 + { print n + m; } // error: non-ghost statements are not allowed in hints m + n; } } @@ -1659,6 +1607,6 @@ module MoreGhostPrintAttempts { module MoreLetSuchThatExpr { method LetSuchThat_Ghost(ghost z: int, n: nat) { - var x := var y :| y < z; y; // error: contraint depend on ghost (z)//ADD:608 + var x := var y :| y < z; y; // error: contraint depend on ghost (z) } } diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index ee2dd5f7..e5506688 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -8,152 +8,152 @@ ResolutionErrors.dfy(137,4): Error: ghost variables are allowed only in specific ResolutionErrors.dfy(141,21): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(142,35): Error: ghost variables are allowed only in specification contexts ResolutionErrors.dfy(151,10): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(251,27): Error: ghost-context break statement is not allowed to break out of non-ghost structure -ResolutionErrors.dfy(274,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop -ResolutionErrors.dfy(288,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop -ResolutionErrors.dfy(293,8): Error: return statement is not allowed in this context (because it is guarded by a specification-only expression) -ResolutionErrors.dfy(375,15): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(464,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(466,14): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(468,10): Error: a hint is not allowed to update a variable declared outside the hint -ResolutionErrors.dfy(558,7): Error: RHS (of type List) not assignable to LHS (of type List) -ResolutionErrors.dfy(563,7): Error: RHS (of type List) not assignable to LHS (of type List) -ResolutionErrors.dfy(577,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) -ResolutionErrors.dfy(589,24): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree -ResolutionErrors.dfy(619,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(619,23): Error: type variable 'T' in the function call to 'P' could not be determined -ResolutionErrors.dfy(626,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(626,23): Error: type variable 'T' in the function call to 'P' could not be determined -ResolutionErrors.dfy(639,13): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(640,9): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(647,14): Error: new allocation not supported in forall statements -ResolutionErrors.dfy(652,11): Error: the body of the enclosing forall statement is not allowed to update heap locations -ResolutionErrors.dfy(652,14): Error: new allocation not allowed in ghost context -ResolutionErrors.dfy(662,23): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(669,15): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(678,17): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(700,21): Error: the type of this variable is underspecified -ResolutionErrors.dfy(751,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(789,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(824,19): Error: calls to methods with side-effects are not allowed inside a statement expression -ResolutionErrors.dfy(826,20): Error: wrong number of method result arguments (got 0, expected 1) -ResolutionErrors.dfy(838,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(848,4): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(859,36): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(868,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(882,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(883,6): Error: RHS (of type int) not assignable to LHS (of type object) -ResolutionErrors.dfy(884,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(889,6): Error: RHS (of type G) not assignable to LHS (of type object) -ResolutionErrors.dfy(890,6): Error: RHS (of type Dt) not assignable to LHS (of type object) -ResolutionErrors.dfy(891,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) -ResolutionErrors.dfy(953,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(954,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(959,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(960,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(961,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(962,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(963,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(964,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(1045,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 -ResolutionErrors.dfy(1046,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C -ResolutionErrors.dfy(1057,7): Error: Duplicate name of top-level declaration: BadSyn2 -ResolutionErrors.dfy(1054,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List -ResolutionErrors.dfy(1055,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1056,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1063,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A -ResolutionErrors.dfy(1066,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1070,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1079,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed -ResolutionErrors.dfy(1082,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1087,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1106,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1113,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P -ResolutionErrors.dfy(1125,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1135,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1140,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1145,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1146,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1151,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1152,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1153,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1176,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -ResolutionErrors.dfy(1178,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -ResolutionErrors.dfy(1283,26): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1284,31): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1285,29): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1295,34): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1311,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1312,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1349,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) -ResolutionErrors.dfy(1359,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1387,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) -ResolutionErrors.dfy(1397,29): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1399,49): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1399,54): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1420,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1420,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1421,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1421,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1422,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1422,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) -ResolutionErrors.dfy(1423,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1423,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) -ResolutionErrors.dfy(1428,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1428,13): Error: arguments must have the same type (got int and #type) -ResolutionErrors.dfy(1429,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1429,13): Error: arguments must have the same type (got int and #module) -ResolutionErrors.dfy(1430,4): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1431,4): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1440,11): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1441,9): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1442,13): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1445,15): Error: type of RHS of let-such-that expression must be boolean (got int) -ResolutionErrors.dfy(1488,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1510,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1511,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1512,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1515,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(1497,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1510,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(1539,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1540,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1541,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1544,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(1532,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1539,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(1568,20): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1461,29): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1463,17): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1579,16): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(1597,12): Error: trying to break out of more loop levels than there are enclosing loops -ResolutionErrors.dfy(1623,16): Error: ghost fields are allowed only in specification contexts -ResolutionErrors.dfy(1630,9): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1636,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost -ResolutionErrors.dfy(1653,8): Error: 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) -ResolutionErrors.dfy(1662,26): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(488,2): Error: More than one anonymous constructor +ResolutionErrors.dfy(241,27): Error: ghost-context break statement is not allowed to break out of non-ghost structure +ResolutionErrors.dfy(264,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(278,12): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(283,8): Error: return statement is not allowed in this context (because it is guarded by a specification-only expression) +ResolutionErrors.dfy(362,15): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(444,13): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(446,16): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(448,12): Error: a hint is not allowed to update a variable declared outside the hint +ResolutionErrors.dfy(535,7): Error: RHS (of type List) not assignable to LHS (of type List) +ResolutionErrors.dfy(540,7): Error: RHS (of type List) not assignable to LHS (of type List) +ResolutionErrors.dfy(554,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) +ResolutionErrors.dfy(566,24): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree +ResolutionErrors.dfy(592,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(592,23): Error: type variable 'T' in the function call to 'P' could not be determined +ResolutionErrors.dfy(599,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(599,23): Error: type variable 'T' in the function call to 'P' could not be determined +ResolutionErrors.dfy(612,13): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(613,9): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(620,14): Error: new allocation not supported in forall statements +ResolutionErrors.dfy(625,11): Error: the body of the enclosing forall statement is not allowed to update heap locations +ResolutionErrors.dfy(625,14): Error: new allocation not allowed in ghost context +ResolutionErrors.dfy(635,23): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(642,15): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(651,17): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(669,21): Error: the type of this variable is underspecified +ResolutionErrors.dfy(709,22): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(742,22): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(773,19): Error: calls to methods with side-effects are not allowed inside a statement expression +ResolutionErrors.dfy(774,20): Error: wrong number of method result arguments (got 0, expected 1) +ResolutionErrors.dfy(786,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(796,4): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(807,36): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(816,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(830,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(831,6): Error: RHS (of type int) not assignable to LHS (of type object) +ResolutionErrors.dfy(832,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(837,6): Error: RHS (of type G) not assignable to LHS (of type object) +ResolutionErrors.dfy(838,6): Error: RHS (of type Dt) not assignable to LHS (of type object) +ResolutionErrors.dfy(839,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) +ResolutionErrors.dfy(901,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(902,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(907,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(908,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(909,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(910,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(911,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(912,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(993,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 +ResolutionErrors.dfy(994,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C +ResolutionErrors.dfy(1005,7): Error: Duplicate name of top-level declaration: BadSyn2 +ResolutionErrors.dfy(1002,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List +ResolutionErrors.dfy(1003,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1004,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1011,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A +ResolutionErrors.dfy(1014,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1018,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1027,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed +ResolutionErrors.dfy(1030,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1035,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1054,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1061,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P +ResolutionErrors.dfy(1073,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1083,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1088,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1093,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1094,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1099,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1100,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1101,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1124,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1126,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1231,26): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1232,31): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1233,29): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1243,34): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1259,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1260,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1297,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) +ResolutionErrors.dfy(1307,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1335,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) +ResolutionErrors.dfy(1345,29): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1347,49): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1347,54): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1368,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1368,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1369,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1369,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1370,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1370,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) +ResolutionErrors.dfy(1371,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1371,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) +ResolutionErrors.dfy(1376,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1376,13): Error: arguments must have the same type (got int and #type) +ResolutionErrors.dfy(1377,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1377,13): Error: arguments must have the same type (got int and #module) +ResolutionErrors.dfy(1378,4): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1379,4): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1388,11): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1389,9): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1390,13): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1393,15): Error: type of RHS of let-such-that expression must be boolean (got int) +ResolutionErrors.dfy(1436,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1458,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1459,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1460,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1463,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1445,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1458,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1487,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1488,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1489,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1492,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1480,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1487,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1516,20): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1409,29): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1411,17): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1527,16): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1545,12): Error: trying to break out of more loop levels than there are enclosing loops +ResolutionErrors.dfy(1571,16): Error: ghost fields are allowed only in specification contexts +ResolutionErrors.dfy(1578,9): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1584,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(1601,8): Error: 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) +ResolutionErrors.dfy(1610,26): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(469,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') ResolutionErrors.dfy(92,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(93,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(95,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(97,18): Error: wrong number of arguments to datatype constructor David (found 2, expected 1) -ResolutionErrors.dfy(494,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called -ResolutionErrors.dfy(499,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called -ResolutionErrors.dfy(500,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called -ResolutionErrors.dfy(502,9): Error: class Lamb does not have an anonymous constructor -ResolutionErrors.dfy(902,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) -ResolutionErrors.dfy(906,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(909,12): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(917,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(927,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(938,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1094,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1097,20): Error: unresolved identifier: x -ResolutionErrors.dfy(1100,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1102,19): Error: unresolved identifier: x -ResolutionErrors.dfy(1104,19): Error: unresolved identifier: x +ResolutionErrors.dfy(475,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called +ResolutionErrors.dfy(480,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called +ResolutionErrors.dfy(481,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called +ResolutionErrors.dfy(483,9): Error: class Lamb does not have an anonymous constructor +ResolutionErrors.dfy(850,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) +ResolutionErrors.dfy(854,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(857,12): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(865,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(875,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(886,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1042,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1045,20): Error: unresolved identifier: x +ResolutionErrors.dfy(1048,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1050,19): Error: unresolved identifier: x +ResolutionErrors.dfy(1052,19): Error: unresolved identifier: x ResolutionErrors.dfy(12,16): Error: 'decreases *' is not allowed on ghost loops ResolutionErrors.dfy(24,11): Error: array selection requires an array2 (got array3) ResolutionErrors.dfy(25,12): Error: sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got array3) @@ -167,36 +167,36 @@ ResolutionErrors.dfy(62,14): Error: accessing member 'M' requires an instance ex ResolutionErrors.dfy(63,7): Error: unresolved identifier: N ResolutionErrors.dfy(66,8): Error: non-function expression (of type int) is called with parameters ResolutionErrors.dfy(67,14): Error: member 'z' does not exist in type 'Global' -ResolutionErrors.dfy(311,4): Error: label shadows an enclosing label -ResolutionErrors.dfy(316,2): Error: duplicate label -ResolutionErrors.dfy(342,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(343,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(345,9): Error: a constructor is allowed to be called only when an object is being allocated -ResolutionErrors.dfy(359,16): Error: arguments must have the same type (got int and DTD_List) -ResolutionErrors.dfy(360,16): Error: arguments must have the same type (got DTD_List and int) -ResolutionErrors.dfy(361,25): Error: arguments must have the same type (got bool and int) -ResolutionErrors.dfy(400,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) -ResolutionErrors.dfy(412,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) -ResolutionErrors.dfy(420,6): Error: arguments to + must be of a numeric type or a collection type (instead got bool) -ResolutionErrors.dfy(425,6): Error: all lines in a calculation must have the same type (got int after bool) -ResolutionErrors.dfy(428,6): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(428,6): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(429,10): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(429,10): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(434,10): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(434,10): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(603,18): Error: unresolved identifier: w -ResolutionErrors.dfy(714,11): Error: lemmas are not allowed to have modifies clauses -ResolutionErrors.dfy(976,9): Error: unresolved identifier: s -ResolutionErrors.dfy(987,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) -ResolutionErrors.dfy(988,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) -ResolutionErrors.dfy(994,16): Error: condition is expected to be of type bool, but is int -ResolutionErrors.dfy(995,16): Error: member 3 does not exist in datatype _tuple#3 -ResolutionErrors.dfy(995,26): Error: member x does not exist in datatype _tuple#2 -ResolutionErrors.dfy(1018,15): Error: arguments to / must have the same type (got real and int) -ResolutionErrors.dfy(1019,10): Error: second argument to % must be of type int (instead got real) -ResolutionErrors.dfy(1164,8): Error: new cannot be applied to a trait -ResolutionErrors.dfy(1185,13): Error: first argument to / must be of numeric type (instead got set) -ResolutionErrors.dfy(1192,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1207,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(301,4): Error: label shadows an enclosing label +ResolutionErrors.dfy(306,2): Error: duplicate label +ResolutionErrors.dfy(332,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(333,4): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(335,9): Error: a constructor is allowed to be called only when an object is being allocated +ResolutionErrors.dfy(349,16): Error: arguments must have the same type (got int and DTD_List) +ResolutionErrors.dfy(350,16): Error: arguments must have the same type (got DTD_List and int) +ResolutionErrors.dfy(351,25): Error: arguments must have the same type (got bool and int) +ResolutionErrors.dfy(387,5): Error: incorrect type of method in-parameter 1 (expected GenericClass, got GenericClass) +ResolutionErrors.dfy(399,18): Error: incorrect type of datatype constructor argument (found GList<_T0>, expected GList) +ResolutionErrors.dfy(407,6): Error: arguments to + must be of a numeric type or a collection type (instead got bool) +ResolutionErrors.dfy(412,6): Error: all lines in a calculation must have the same type (got int after bool) +ResolutionErrors.dfy(415,6): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(415,6): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(416,10): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(416,10): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(421,10): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(421,10): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(580,18): Error: unresolved identifier: w +ResolutionErrors.dfy(683,11): Error: lemmas are not allowed to have modifies clauses +ResolutionErrors.dfy(924,9): Error: unresolved identifier: s +ResolutionErrors.dfy(935,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) +ResolutionErrors.dfy(936,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) +ResolutionErrors.dfy(942,16): Error: condition is expected to be of type bool, but is int +ResolutionErrors.dfy(943,16): Error: member 3 does not exist in datatype _tuple#3 +ResolutionErrors.dfy(943,26): Error: member x does not exist in datatype _tuple#2 +ResolutionErrors.dfy(966,15): Error: arguments to / must have the same type (got real and int) +ResolutionErrors.dfy(967,10): Error: second argument to % must be of type int (instead got real) +ResolutionErrors.dfy(1112,8): Error: new cannot be applied to a trait +ResolutionErrors.dfy(1133,13): Error: first argument to / must be of numeric type (instead got set) +ResolutionErrors.dfy(1140,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1155,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating 201 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From aec9290fbd3ca9ada5a7fad4dabb4ed1ffad6a84 Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 28 Sep 2015 13:31:26 -0700 Subject: Additional tests --- Test/dafny0/CoPrefix.dfy | 32 ++++++++++++++++++++++++++++++++ Test/dafny0/CoPrefix.dfy.expect | 17 ++++++++++++++++- Test/dafny0/ResolutionErrors.dfy | 9 +++++++++ Test/dafny0/ResolutionErrors.dfy.expect | 3 ++- 4 files changed, 59 insertions(+), 2 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Test/dafny0/CoPrefix.dfy b/Test/dafny0/CoPrefix.dfy index 0becb24d..3b6bd670 100644 --- a/Test/dafny0/CoPrefix.dfy +++ b/Test/dafny0/CoPrefix.dfy @@ -192,3 +192,35 @@ module Recursion { } } } + +module PrefixEquality { + codatatype Stream = Cons(head: T, Stream) + + colemma Test0(s: Stream, t: Stream) + requires s.head == t.head + { + calc { + s; + ==#[_k-1] + t; // error: this step might not hold + ==#[if 2 <= _k then _k-2 else _k-1] + s; // error: this step might not hold + ==#[0] + t; + } + } + + colemma Test1(s: Stream, t: Stream) + requires s == t + { + calc { + s; + ==#[_k-1] + t; + ==#[_k-2] // error: prefix-equality limit must be at least 0 + s; + ==#[0] + t; + } + } +} diff --git a/Test/dafny0/CoPrefix.dfy.expect b/Test/dafny0/CoPrefix.dfy.expect index a7295367..b42f2593 100644 --- a/Test/dafny0/CoPrefix.dfy.expect +++ b/Test/dafny0/CoPrefix.dfy.expect @@ -12,6 +12,21 @@ CoPrefix.dfy(176,10): Error: cannot prove termination; try supplying a decreases Execution trace: (0,0): anon0 (0,0): anon3_Then +CoPrefix.dfy(205,6): Error: the calculation step between the previous line and this line might not hold +Execution trace: + (0,0): anon0 + (0,0): anon8_Then + (0,0): anon10_Then +CoPrefix.dfy(207,6): Error: the calculation step between the previous line and this line might not hold +Execution trace: + (0,0): anon0 + (0,0): anon8_Then + (0,0): anon11_Then +CoPrefix.dfy(220,12): Error: prefix-equality limit must be at least 0 +Execution trace: + (0,0): anon0 + (0,0): anon8_Then + (0,0): anon11_Then CoPrefix.dfy(63,56): Error: failure to decrease termination measure Execution trace: (0,0): anon0 @@ -47,4 +62,4 @@ Execution trace: (0,0): anon0 (0,0): anon3_Else -Dafny program verifier finished with 41 verified, 9 errors +Dafny program verifier finished with 43 verified, 12 errors diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index a4161a46..9d4d67f1 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -1610,3 +1610,12 @@ module MoreLetSuchThatExpr { var x := var y :| y < z; y; // error: contraint depend on ghost (z) } } + +module UnderspecifiedTypedShouldBeResolvedOnlyOnce { + method CalcTest0(s: seq) { + calc { + 2; + var t :| true; 2; // error: type of 't' is underspecified + } + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index e5506688..6f4b3519 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -132,6 +132,7 @@ ResolutionErrors.dfy(1578,9): Error: ghost variables are allowed only in specifi ResolutionErrors.dfy(1584,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost ResolutionErrors.dfy(1601,8): Error: 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) ResolutionErrors.dfy(1610,26): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1618,6): Error: the type of the bound variable 't' could not be determined ResolutionErrors.dfy(469,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -199,4 +200,4 @@ ResolutionErrors.dfy(1112,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1133,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1140,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1155,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -201 resolution/type errors detected in ResolutionErrors.dfy +202 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 49706a5d1599f9167cb627a305d4abb32cc71edb Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 28 Sep 2015 15:36:45 -0700 Subject: Removed more traces of the previous resolution checks that happened during pass 0. Fixed resolution of specification components of alternative loops. --- Source/Dafny/Resolver.cs | 294 ++++++++++++++++---------------- Test/dafny0/ResolutionErrors.dfy | 215 +++++++++++++++-------- Test/dafny0/ResolutionErrors.dfy.expect | 275 ++++++++++++++--------------- 3 files changed, 430 insertions(+), 354 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index ec3a69c9..f4fac31b 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -1368,7 +1368,7 @@ namespace Microsoft.Dafny var added = scope.Push(dd.Var.Name, dd.Var); Contract.Assert(added == Scope.PushResult.Success); ResolveType(dd.Var.tok, dd.Var.Type, dd, ResolveTypeOptionEnum.DontInfer, null); - ResolveExpression(dd.Constraint, new ResolveOpts(dd, false, true)); + ResolveExpression(dd.Constraint, new ResolveOpts(dd, false)); Contract.Assert(dd.Constraint.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(dd.Constraint.Type, Type.Bool, dd.Constraint, "newtype constraint must be of type bool (instead got {0})", dd.Constraint.Type); SolveAllTypeConstraints(); @@ -3129,6 +3129,12 @@ namespace Microsoft.Dafny Contract.Requires(msgArgs != null); resolver.reporter.Error(MessageSource.Resolver, expr, msg, msgArgs); } + protected void Error(IToken tok, string msg, params object[] msgArgs) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Contract.Requires(msgArgs != null); + resolver.reporter.Error(MessageSource.Resolver, tok, msg, msgArgs); + } /// /// This method does three things: /// 0. Reports an error if "mustBeErasable" and the statement assigns to a non-ghost field @@ -3219,6 +3225,9 @@ namespace Microsoft.Dafny var gk = AssignStmt.LhsIsToGhost_Which(lhs); if (gk == AssignStmt.NonGhostKind.IsGhost) { s.IsGhost = true; + if (s.Rhs is TypeRhs) { + Error(s.Rhs.Tok, "'new' is not allowed in ghost contexts"); + } } else if (gk == AssignStmt.NonGhostKind.Variable && codeContext.IsGhost) { // cool } else if (mustBeErasable) { @@ -3322,6 +3331,9 @@ namespace Microsoft.Dafny if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) { Error(s, "'decreases *' is not allowed on ghost loops"); } + if (s.IsGhost && s.Mod.Expressions != null) { + s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers); + } if (s.Body != null) { Visit(s.Body, s.IsGhost); } @@ -3330,6 +3342,12 @@ namespace Microsoft.Dafny } else if (stmt is AlternativeLoopStmt) { var s = (AlternativeLoopStmt)stmt; s.IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard)); + if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) { + Error(s, "'decreases *' is not allowed on ghost loops"); + } + if (s.IsGhost && s.Mod.Expressions != null) { + s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers); + } s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.IsGhost))); s.IsGhost = s.IsGhost || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost))); @@ -3343,10 +3361,13 @@ namespace Microsoft.Dafny } else if (stmt is ModifyStmt) { var s = (ModifyStmt)stmt; + s.IsGhost = mustBeErasable; + if (s.IsGhost) { + s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers); + } if (s.Body != null) { Visit(s.Body, mustBeErasable); } - s.IsGhost = mustBeErasable; } else if (stmt is CalcStmt) { var s = (CalcStmt)stmt; @@ -3999,7 +4020,6 @@ namespace Microsoft.Dafny void ResolveAttributes(Attributes attrs, ResolveOpts opts) { Contract.Requires(opts != null); - Contract.Requires(opts.DontCareAboutCompilation); // attributes are never compiled // order does not matter much for resolution, so resolve them in reverse order foreach (var attr in attrs.AsEnumerable()) { if (attr.Args != null) { @@ -4093,23 +4113,23 @@ namespace Microsoft.Dafny foreach (Formal p in f.Formals) { scope.Push(p.Name, p); } - ResolveAttributes(f.Attributes, new ResolveOpts(f, false, true)); + ResolveAttributes(f.Attributes, new ResolveOpts(f, false)); foreach (Expression r in f.Req) { - ResolveExpression(r, new ResolveOpts(f, false, true)); + ResolveExpression(r, new ResolveOpts(f, false)); Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(r.Type, Type.Bool, r, "Precondition must be a boolean (got {0})", r.Type); } foreach (FrameExpression fr in f.Reads) { - ResolveFrameExpression(fr, true, f.IsGhost, f); + ResolveFrameExpression(fr, true, f); } foreach (Expression r in f.Ens) { - ResolveExpression(r, new ResolveOpts(f, false, true)); // since this is a function, the postcondition is still a one-state predicate + ResolveExpression(r, new ResolveOpts(f, false)); // since this is a function, the postcondition is still a one-state predicate Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(r.Type, Type.Bool, r, "Postcondition must be a boolean (got {0})", r.Type); } - ResolveAttributes(f.Decreases.Attributes, new ResolveOpts(f, false, true)); + ResolveAttributes(f.Decreases.Attributes, new ResolveOpts(f, false)); foreach (Expression r in f.Decreases.Expressions) { - ResolveExpression(r, new ResolveOpts(f, false, true)); + ResolveExpression(r, new ResolveOpts(f, false)); // any type is fine } SolveAllTypeConstraints(); @@ -4126,14 +4146,11 @@ namespace Microsoft.Dafny /// /// /// - /// /// True indicates "reads", false indicates "modifies". - /// - /// - void ResolveFrameExpression(FrameExpression fe, bool readsFrame, bool isGhostContext, ICodeContext codeContext) { + void ResolveFrameExpression(FrameExpression fe, bool readsFrame, ICodeContext codeContext) { Contract.Requires(fe != null); Contract.Requires(codeContext != null); - ResolveExpression(fe.E, new ResolveOpts(codeContext, false, true /* yes, this is ghost */)); + ResolveExpression(fe.E, new ResolveOpts(codeContext, false)); Type t = fe.E.Type; Contract.Assert(t != null); // follows from postcondition of ResolveExpression var arrTy = t.AsArrowType; @@ -4153,8 +4170,6 @@ namespace Microsoft.Dafny // error has already been reported by ResolveMember } else if (!(member is Field)) { reporter.Error(MessageSource.Resolver, fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, ctype.Name); - } else if (!readsFrame && isGhostContext && !member.IsGhost) { - reporter.Error(MessageSource.Resolver, fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName); } else { Contract.Assert(ctype != null && ctype.ResolvedClass != null); // follows from postcondition of ResolveMember fe.Field = (Field)member; @@ -4162,6 +4177,17 @@ namespace Microsoft.Dafny } } + /// + /// This method can be called even if the resolution of "fe" failed; in that case, this method will + /// not issue any error message. + /// + void DisallowNonGhostFieldSpecifiers(FrameExpression fe) { + Contract.Requires(fe != null); + if (fe.Field != null && !fe.Field.IsGhost) { + reporter.Error(MessageSource.Resolver, fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName); + } + } + /// /// Assumes type parameters have already been pushed /// @@ -4206,25 +4232,24 @@ namespace Microsoft.Dafny // Start resolving specification... foreach (MaybeFreeExpression e in m.Req) { - ResolveAttributes(e.Attributes, new ResolveOpts(m, false, true)); - ResolveExpression(e.E, new ResolveOpts(m, false, true)); + ResolveAttributes(e.Attributes, new ResolveOpts(m, false)); + ResolveExpression(e.E, new ResolveOpts(m, false)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Precondition must be a boolean (got {0})", e.E.Type); } - ResolveAttributes(m.Mod.Attributes, new ResolveOpts(m, false, true)); + ResolveAttributes(m.Mod.Attributes, new ResolveOpts(m, false)); foreach (FrameExpression fe in m.Mod.Expressions) { - ResolveFrameExpression(fe, false, m.IsGhost, m); + ResolveFrameExpression(fe, false, m); if (m is Lemma || m is FixpointLemma) { reporter.Error(MessageSource.Resolver, fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind); + } else if (m.IsGhost) { + DisallowNonGhostFieldSpecifiers(fe); } } - ResolveAttributes(m.Decreases.Attributes, new ResolveOpts(m, false, true)); + ResolveAttributes(m.Decreases.Attributes, new ResolveOpts(m, false)); foreach (Expression e in m.Decreases.Expressions) { - ResolveExpression(e, new ResolveOpts(m, false, true)); + ResolveExpression(e, new ResolveOpts(m, false)); // any type is fine - if (m.IsGhost && e is WildcardExpr) { - reporter.Error(MessageSource.Resolver, e, "'decreases *' is not allowed on ghost methods"); - } } // Add out-parameters to a new scope that will also include the outermost-level locals of the body @@ -4240,8 +4265,8 @@ namespace Microsoft.Dafny // ... continue resolving specification foreach (MaybeFreeExpression e in m.Ens) { - ResolveAttributes(e.Attributes, new ResolveOpts(m, true, true)); - ResolveExpression(e.E, new ResolveOpts(m, true, true)); + ResolveAttributes(e.Attributes, new ResolveOpts(m, true)); + ResolveExpression(e.E, new ResolveOpts(m, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Postcondition must be a boolean (got {0})", e.E.Type); } @@ -4265,7 +4290,7 @@ namespace Microsoft.Dafny } // attributes are allowed to mention both in- and out-parameters (including the implicit _k, for colemmas) - ResolveAttributes(m.Attributes, new ResolveOpts(m, false, true)); + ResolveAttributes(m.Attributes, new ResolveOpts(m, false)); scope.PopMarker(); // for the out-parameters and outermost-level locals scope.PopMarker(); // for the in-parameters @@ -4331,20 +4356,20 @@ namespace Microsoft.Dafny Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count); for (int i = 0; i < iter.Decreases.Expressions.Count; i++) { var e = iter.Decreases.Expressions[i]; - ResolveExpression(e, new ResolveOpts(iter, false, true)); + ResolveExpression(e, new ResolveOpts(iter, false)); // any type is fine, but associate this type with the corresponding _decreases field var d = iter.DecreasesFields[i]; // If the following type constraint does not hold, then: Bummer, there was a use--and a bad use--of the field before, so this won't be the best of error messages ConstrainTypes(d.Type, e.Type, e, "type of field {0} is {1}, but has been constrained elsewhere to be of type {2}", d.Name, e.Type, d.Type); } foreach (FrameExpression fe in iter.Reads.Expressions) { - ResolveFrameExpression(fe, true, false, iter); + ResolveFrameExpression(fe, true, iter); } foreach (FrameExpression fe in iter.Modifies.Expressions) { - ResolveFrameExpression(fe, false, false, iter); + ResolveFrameExpression(fe, false, iter); } foreach (MaybeFreeExpression e in iter.Requires) { - ResolveExpression(e.E, new ResolveOpts(iter, false, true)); + ResolveExpression(e.E, new ResolveOpts(iter, false)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Precondition must be a boolean (got {0})", e.E.Type); } @@ -4358,22 +4383,22 @@ namespace Microsoft.Dafny Contract.Assert(scope.AllowInstance); foreach (MaybeFreeExpression e in iter.YieldRequires) { - ResolveExpression(e.E, new ResolveOpts(iter, false, true)); + ResolveExpression(e.E, new ResolveOpts(iter, false)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Yield precondition must be a boolean (got {0})", e.E.Type); } foreach (MaybeFreeExpression e in iter.YieldEnsures) { - ResolveExpression(e.E, new ResolveOpts(iter, true, true)); + ResolveExpression(e.E, new ResolveOpts(iter, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Yield postcondition must be a boolean (got {0})", e.E.Type); } foreach (MaybeFreeExpression e in iter.Ensures) { - ResolveExpression(e.E, new ResolveOpts(iter, true, true)); + ResolveExpression(e.E, new ResolveOpts(iter, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.E.Type, Type.Bool, e.E, "Postcondition must be a boolean (got {0})", e.E.Type); } - ResolveAttributes(iter.Attributes, new ResolveOpts(iter, false, true)); + ResolveAttributes(iter.Attributes, new ResolveOpts(iter, false)); var postSpecErrorCount = reporter.Count(ErrorLevel.Error); @@ -4687,13 +4712,13 @@ namespace Microsoft.Dafny } var prevErrorCount = reporter.Count(ErrorLevel.Error); if (t.NamePath is ExprDotName) { - var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true, true), allowDanglingDotName, option, defaultTypeArguments); + var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true), allowDanglingDotName, option, defaultTypeArguments); if (ret != null) { return ret; } } else { var s = (NameSegment)t.NamePath; - ResolveNameSegment_Type(s, new ResolveOpts(context, true, true), option, defaultTypeArguments); + ResolveNameSegment_Type(s, new ResolveOpts(context, true), option, defaultTypeArguments); } if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var r = t.NamePath.Resolved as Resolver_IdentifierExpr; @@ -5225,17 +5250,17 @@ namespace Microsoft.Dafny Contract.Requires(stmt != null); Contract.Requires(codeContext != null); if (!(stmt is ForallStmt)) { // forall statements do their own attribute resolution below - ResolveAttributes(stmt.Attributes, new ResolveOpts(codeContext, true, true)); + ResolveAttributes(stmt.Attributes, new ResolveOpts(codeContext, true)); } if (stmt is PredicateStmt) { PredicateStmt s = (PredicateStmt)stmt; - ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, true)); + ResolveExpression(s.Expr, new ResolveOpts(codeContext, true)); Contract.Assert(s.Expr.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type); } else if (stmt is PrintStmt) { var s = (PrintStmt)stmt; - var opts = new ResolveOpts(codeContext, false, specContextOnly); + var opts = new ResolveOpts(codeContext, false); s.Args.Iter(e => ResolveExpression(e, opts)); } else if (stmt is BreakStmt) { @@ -5346,7 +5371,7 @@ namespace Microsoft.Dafny } // With the new locals in scope, it's now time to resolve the attributes on all the locals foreach (var local in s.Locals) { - ResolveAttributes(local.Attributes, new ResolveOpts(codeContext, true, true)); + ResolveAttributes(local.Attributes, new ResolveOpts(codeContext, true)); } // Resolve the AssignSuchThatStmt, if any if (s.Update is AssignSuchThatStmt) { @@ -5374,18 +5399,16 @@ namespace Microsoft.Dafny } else if (stmt is AssignStmt) { AssignStmt s = (AssignStmt)stmt; int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true, specContextOnly)); // allow ghosts for now, tighted up below + ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true)); // allow ghosts for now, tighted up below bool lhsResolvedSuccessfully = reporter.Count(ErrorLevel.Error) == prevErrorCount; Contract.Assert(s.Lhs.Type != null); // follows from postcondition of ResolveExpression // check that LHS denotes a mutable variable or a field - bool lvalueIsGhost = false; var lhs = s.Lhs.Resolved; if (lhs is IdentifierExpr) { IVariable var = ((IdentifierExpr)lhs).Var; if (var == null) { // the LHS didn't resolve correctly; some error would already have been reported } else { - lvalueIsGhost = var.IsGhost || codeContext.IsGhost; CheckIsLvalue(lhs, codeContext); var localVar = var as LocalVariable; @@ -5411,7 +5434,6 @@ namespace Microsoft.Dafny } else if (lhs is MemberSelectExpr) { var fse = (MemberSelectExpr)lhs; if (fse.Member != null) { // otherwise, an error was reported above - lvalueIsGhost = fse.Member.IsGhost; CheckIsLvalue(fse, codeContext); } } else if (lhs is SeqSelectExpr) { @@ -5432,12 +5454,12 @@ namespace Microsoft.Dafny Type lhsType = s.Lhs.Type; if (s.Rhs is ExprRhs) { ExprRhs rr = (ExprRhs)s.Rhs; - ResolveExpression(rr.Expr, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(rr.Expr, new ResolveOpts(codeContext, true)); Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(lhsType, rr.Expr.Type, stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType); } else if (s.Rhs is TypeRhs) { TypeRhs rr = (TypeRhs)s.Rhs; - Type t = ResolveTypeRhs(rr, stmt, lvalueIsGhost, codeContext); + Type t = ResolveTypeRhs(rr, stmt, codeContext); ConstrainTypes(lhsType, t, stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType); } else if (s.Rhs is HavocRhs) { // nothing else to do @@ -5447,7 +5469,7 @@ namespace Microsoft.Dafny } else if (stmt is CallStmt) { CallStmt s = (CallStmt)stmt; - ResolveCallStmt(s, specContextOnly, codeContext, null); + ResolveCallStmt(s, codeContext, null); } else if (stmt is BlockStmt) { var s = (BlockStmt)stmt; @@ -5460,7 +5482,7 @@ namespace Microsoft.Dafny bool branchesAreSpecOnly = specContextOnly; if (s.Guard != null) { int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(s.Guard, new ResolveOpts(codeContext, true)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); @@ -5483,7 +5505,7 @@ namespace Microsoft.Dafny var fvs = new HashSet(); if (s.Guard != null) { int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(s.Guard, new ResolveOpts(codeContext, true)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; Translator.ComputeFreeVariables(s.Guard, fvs); @@ -5493,34 +5515,8 @@ namespace Microsoft.Dafny } } - foreach (MaybeFreeExpression inv in s.Invariants) { - ResolveAttributes(inv.Attributes, new ResolveOpts(codeContext, true, true)); - ResolveExpression(inv.E, new ResolveOpts(codeContext, true, true)); - Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression - Translator.ComputeFreeVariables(inv.E, fvs); - ConstrainTypes(inv.E.Type, Type.Bool, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); - } + ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, fvs); - ResolveAttributes(s.Decreases.Attributes, new ResolveOpts(codeContext, true, true)); - foreach (Expression e in s.Decreases.Expressions) { - ResolveExpression(e, new ResolveOpts(codeContext, true, true)); - if (e is WildcardExpr) { - if (bodyMustBeSpecOnly) { - reporter.Error(MessageSource.Resolver, e, "'decreases *' is not allowed on ghost loops"); - } else if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) { - reporter.Error(MessageSource.Resolver, e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); - } - } - // any type is fine - } - - if (s.Mod.Expressions != null) { - ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true, true)); - foreach (FrameExpression fe in s.Mod.Expressions) { - ResolveFrameExpression(fe, false, bodyMustBeSpecOnly, codeContext); - Translator.ComputeFreeVariables(fe.E, fvs); - } - } if (s.Body != null) { loopStack.Add(s); // push if (s.Labels == null) { // otherwise, "s" is already in "inSpecOnlyContext" map @@ -5537,21 +5533,7 @@ namespace Microsoft.Dafny } else if (stmt is AlternativeLoopStmt) { var s = (AlternativeLoopStmt)stmt; ResolveAlternatives(s.Alternatives, specContextOnly, s, codeContext); - foreach (MaybeFreeExpression inv in s.Invariants) { - ResolveExpression(inv.E, new ResolveOpts(codeContext, true, true)); - Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression - ConstrainTypes(inv.E.Type, Type.Bool, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); - } - - foreach (Expression e in s.Decreases.Expressions) { - ResolveExpression(e, new ResolveOpts(codeContext, true, true)); - if (e is WildcardExpr) { - if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) { - reporter.Error(MessageSource.Resolver, e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); - } - } - // any type is fine - } + ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, null); } else if (stmt is ForallStmt) { var s = (ForallStmt)stmt; @@ -5562,17 +5544,17 @@ namespace Microsoft.Dafny ScopePushAndReport(scope, v, "local-variable"); ResolveType(v.tok, v.Type, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null); } - ResolveExpression(s.Range, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(s.Range, new ResolveOpts(codeContext, true)); Contract.Assert(s.Range.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(s.Range.Type, Type.Bool, stmt, "range restriction in forall statement must be of type bool (instead got {0})", s.Range.Type); foreach (var ens in s.Ens) { - ResolveExpression(ens.E, new ResolveOpts(codeContext, true, true)); + ResolveExpression(ens.E, new ResolveOpts(codeContext, true)); Contract.Assert(ens.E.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(ens.E.Type, Type.Bool, ens.E, "ensures condition is expected to be of type {0}, but is {1}", Type.Bool, ens.E.Type); } // Since the range and postconditions are more likely to infer the types of the bound variables, resolve them // first (above) and only then resolve the attributes (below). - ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true, true)); + ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true)); bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == reporter.Count(ErrorLevel.Error) && UsesSpecFeatures(s.Range)); if (!bodyMustBeSpecOnly && prevErrorCount == reporter.Count(ErrorLevel.Error)) { @@ -5637,10 +5619,9 @@ namespace Microsoft.Dafny } else if (stmt is ModifyStmt) { var s = (ModifyStmt)stmt; - ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true, true)); + ResolveAttributes(s.Mod.Attributes, new ResolveOpts(codeContext, true)); foreach (FrameExpression fe in s.Mod.Expressions) { - // (yes, say "modifies", not "modify", in the next line -- it seems to give a more readable error message - ResolveFrameExpression(fe, false, specContextOnly, codeContext); + ResolveFrameExpression(fe, false, codeContext); } if (s.Body != null) { ResolveBlockStatement(s.Body, specContextOnly, codeContext); @@ -5651,17 +5632,17 @@ namespace Microsoft.Dafny CalcStmt s = (CalcStmt)stmt; if (s.Lines.Count > 0) { var e0 = s.Lines.First(); - ResolveExpression(e0, new ResolveOpts(codeContext, true, true)); + ResolveExpression(e0, new ResolveOpts(codeContext, true)); Contract.Assert(e0.Type != null); // follows from postcondition of ResolveExpression for (int i = 1; i < s.Lines.Count; i++) { if (i < s.Lines.Count - 1 || prevErrorCount == reporter.Count(ErrorLevel.Error)) { // do not resolve the dummy step if there were errors, it might generate more errors var e1 = s.Lines[i]; - ResolveExpression(e1, new ResolveOpts(codeContext, true, true)); + ResolveExpression(e1, new ResolveOpts(codeContext, true)); Contract.Assert(e1.Type != null); // follows from postcondition of ResolveExpression if (!ConstrainTypes(e0.Type, e1.Type, e1, "all lines in a calculation must have the same type (got {0} after {1})", e1.Type, e0.Type)) { } else { var step = s.StepOps[i - 1].StepExpr(e0, e1); // Use custom line operator - ResolveExpression(step, new ResolveOpts(codeContext, true, true)); + ResolveExpression(step, new ResolveOpts(codeContext, true)); s.Steps.Add(step); } e0 = e1; @@ -5686,7 +5667,7 @@ namespace Microsoft.Dafny } else { s.Result = CalcStmt.DefaultOp.StepExpr(Expression.CreateIntLiteral(s.Tok, 0), Expression.CreateIntLiteral(s.Tok, 0)); } - ResolveExpression(s.Result, new ResolveOpts(codeContext, true, true)); + ResolveExpression(s.Result, new ResolveOpts(codeContext, true)); Contract.Assert(s.Result != null); Contract.Assert(prevErrorCount != reporter.Count(ErrorLevel.Error) || s.Steps.Count == s.Hints.Count); @@ -5704,13 +5685,51 @@ namespace Microsoft.Dafny } } + private void ResolveLoopSpecificationComponents(List invariants, Specification decreases, Specification modifies, ICodeContext codeContext, HashSet fvs) { + Contract.Requires(invariants != null); + Contract.Requires(decreases != null); + Contract.Requires(modifies != null); + Contract.Requires(codeContext != null); + + foreach (MaybeFreeExpression inv in invariants) { + ResolveAttributes(inv.Attributes, new ResolveOpts(codeContext, true)); + ResolveExpression(inv.E, new ResolveOpts(codeContext, true)); + Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression + if (fvs != null) { + Translator.ComputeFreeVariables(inv.E, fvs); + } + ConstrainTypes(inv.E.Type, Type.Bool, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); + } + + ResolveAttributes(decreases.Attributes, new ResolveOpts(codeContext, true)); + foreach (Expression e in decreases.Expressions) { + ResolveExpression(e, new ResolveOpts(codeContext, true)); + if (e is WildcardExpr) { + if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) { + reporter.Error(MessageSource.Resolver, e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); + } + } + // any type is fine + } + + ResolveAttributes(modifies.Attributes, new ResolveOpts(codeContext, true)); + if (modifies.Expressions != null) { + foreach (FrameExpression fe in modifies.Expressions) { + ResolveFrameExpression(fe, false, codeContext); + if (fvs != null) { + Translator.ComputeFreeVariables(fe.E, fvs); + } + } + } + } + void ResolveMatchStmt(Statement stmt, bool specContextOnly, ICodeContext codeContext) { MatchStmt s = (MatchStmt)stmt; DesugarMatchStmtWithTupleExpression(s); bool bodyIsSpecOnly = specContextOnly; int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveExpression(s.Source, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(s.Source, new ResolveOpts(codeContext, true)); Contract.Assert(s.Source.Type != null); // follows from postcondition of ResolveExpression bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; if (!specContextOnly && successfullyResolved) { @@ -6230,7 +6249,7 @@ namespace Microsoft.Dafny var lhsNameSet = new HashSet(); // used to check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification) foreach (var lhs in s.Lhss) { var ec = reporter.Count(ErrorLevel.Error); - ResolveExpression(lhs, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(lhs, new ResolveOpts(codeContext, true)); if (ec == reporter.Count(ErrorLevel.Error)) { if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) { reporter.Error(MessageSource.Resolver, lhs, "cannot assign to a range of array elements (try the 'forall' statement)"); @@ -6241,11 +6260,11 @@ namespace Microsoft.Dafny // Resolve RHSs if (update == null) { var suchThat = (AssignSuchThatStmt)s; // this is the other possible subclass - ResolveAssignSuchThatStmt(suchThat, specContextOnly, codeContext); + ResolveAssignSuchThatStmt(suchThat, codeContext); } else { ResolveUpdateStmt(update, specContextOnly, codeContext, errorCountBeforeCheckingLhs); } - ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true, true)); + ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true)); } /// /// Resolve the RHSs and entire UpdateStmt (LHSs should already have been checked by the caller). @@ -6262,7 +6281,7 @@ namespace Microsoft.Dafny bool isEffectful; if (rhs is TypeRhs) { var tr = (TypeRhs)rhs; - ResolveTypeRhs(tr, update, specContextOnly, codeContext); + ResolveTypeRhs(tr, update, codeContext); isEffectful = tr.InitCall != null; } else if (rhs is HavocRhs) { isEffectful = false; @@ -6270,17 +6289,11 @@ namespace Microsoft.Dafny var er = (ExprRhs)rhs; if (er.Expr is ApplySuffix) { var a = (ApplySuffix)er.Expr; - // Note, in the following line, the dontCareAboutCompilation could be more precise. It could be computed as in the else - // branch if the ApplySuffix is really just the RHS of an assignment. However, if "update" is really a call statement, - // then we should not let the LHS influence the call to ResolveApplySuffix. Unfortunately, we don't know which case - // we're in until ResolveApplySuffix has returned (where a non-null cRhs indicates that "update" is a call statement). - // So, we'll be conservative and will simply pass in specContextOnly here. - var cRhs = ResolveApplySuffix(a, new ResolveOpts(codeContext, true, specContextOnly/*see note on previous line*/), true); + var cRhs = ResolveApplySuffix(a, new ResolveOpts(codeContext, true), true); isEffectful = cRhs != null; methodCallInfo = methodCallInfo ?? cRhs; } else { - var dontCareAboutCompilation = specContextOnly || (j < update.Lhss.Count && AssignStmt.LhsIsToGhost(update.Lhss[j])); - ResolveExpression(er.Expr, new ResolveOpts(codeContext, true, dontCareAboutCompilation)); + ResolveExpression(er.Expr, new ResolveOpts(codeContext, true)); isEffectful = false; } } @@ -6355,7 +6368,7 @@ namespace Microsoft.Dafny } } - private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, bool specContextOnly, ICodeContext codeContext) { + private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, ICodeContext codeContext) { Contract.Requires(s != null); Contract.Requires(codeContext != null); @@ -6373,7 +6386,7 @@ namespace Microsoft.Dafny } var ec = reporter.Count(ErrorLevel.Error); - ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(s.Expr, new ResolveOpts(codeContext, true)); ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type); } @@ -6384,7 +6397,7 @@ namespace Microsoft.Dafny // first, resolve the guards, which tells us whether or not the entire statement is a ghost statement foreach (var alternative in alternatives) { int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true, specContextOnly)); + ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true)); Contract.Assert(alternative.Guard.Type != null); // follows from postcondition of ResolveExpression bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; ConstrainTypes(alternative.Guard.Type, Type.Bool, alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type); @@ -6412,7 +6425,7 @@ namespace Microsoft.Dafny /// Resolves the given call statement. /// Assumes all LHSs have already been resolved (and checked for mutability). /// - void ResolveCallStmt(CallStmt s, bool specContextOnly, ICodeContext codeContext, Type receiverType) { + void ResolveCallStmt(CallStmt s, ICodeContext codeContext, Type receiverType) { Contract.Requires(s != null); Contract.Requires(codeContext != null); bool isInitCall = receiverType != null; @@ -6430,8 +6443,7 @@ namespace Microsoft.Dafny // resolve arguments int j = 0; foreach (Expression e in s.Args) { - bool allowGhost = callee.Ins.Count <= j || callee.Ins[j].IsGhost; - ResolveExpression(e, new ResolveOpts(codeContext, true, allowGhost)); + ResolveExpression(e, new ResolveOpts(codeContext, true)); j++; } @@ -6827,16 +6839,12 @@ namespace Microsoft.Dafny } } - Type ResolveTypeRhs(TypeRhs rr, Statement stmt, bool specContextOnly, ICodeContext codeContext) { + Type ResolveTypeRhs(TypeRhs rr, Statement stmt, ICodeContext codeContext) { Contract.Requires(rr != null); Contract.Requires(stmt != null); Contract.Requires(codeContext != null); Contract.Ensures(Contract.Result() != null); - // "new" is not allowed in ghost contexts - if (specContextOnly) { - reporter.Error(MessageSource.Resolver, rr.Tok, "'new' is not allowed in ghost contexts"); - } if (rr.Type == null) { if (rr.ArrayDimensions != null) { // ---------- new T[EE] @@ -6888,13 +6896,13 @@ namespace Microsoft.Dafny // type, create an dot-suffix expression around this receiver, and then resolve it in the usual way for dot-suffix expressions. var lhs = new ImplicitThisExpr(initCallTok) { Type = rr.EType }; var callLhs = new ExprDotName(initCallTok, lhs, initCallName, ret == null ? null : ret.LastComponent.OptTypeArguments); - ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true, specContextOnly), true); + ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true), true); if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { Contract.Assert(callLhs.ResolvedExpression is MemberSelectExpr); // since ResolveApplySuffix succeeded and call.Lhs denotes an expression (not a module or a type) var methodSel = (MemberSelectExpr)callLhs.ResolvedExpression; if (methodSel.Member is Method) { rr.InitCall = new CallStmt(initCallTok, stmt.EndTok, new List(), methodSel, rr.Arguments); - ResolveCallStmt(rr.InitCall, specContextOnly, codeContext, rr.EType); + ResolveCallStmt(rr.InitCall, codeContext, rr.EType); if (rr.InitCall.Method is Constructor) { callsConstructor = true; } @@ -7170,24 +7178,10 @@ namespace Microsoft.Dafny { public readonly ICodeContext codeContext; public readonly bool twoState; - public readonly bool DontCareAboutCompilation; public ResolveOpts(ICodeContext codeContext, bool twoState) { Contract.Requires(codeContext != null); this.codeContext = codeContext; this.twoState = twoState; - DontCareAboutCompilation = codeContext.IsGhost; - } - public ResolveOpts(ICodeContext codeContext, bool twoState, bool dontCareAboutCompilation) { - Contract.Requires(codeContext != null); - this.codeContext = codeContext; - this.twoState = twoState; - this.DontCareAboutCompilation = dontCareAboutCompilation; - } - public ResolveOpts(ResolveOpts r, bool dontCareAboutCompilation) { - Contract.Requires(r != null); - this.codeContext = r.codeContext; - this.twoState = r.twoState; - this.DontCareAboutCompilation = dontCareAboutCompilation; } } @@ -7846,7 +7840,7 @@ namespace Microsoft.Dafny } } ResolveExpression(e.Body, opts); - ResolveAttributes(e.Attributes, new ResolveOpts(opts, true)); + ResolveAttributes(e.Attributes, opts); scope.PopMarker(); expr.Type = e.Body.Type; @@ -7873,16 +7867,16 @@ namespace Microsoft.Dafny reporter.Error(MessageSource.Resolver, expr, "a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier"); } if (e.Range != null) { - ResolveExpression(e.Range, new ResolveOpts(opts, true)); + ResolveExpression(e.Range, opts); Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.Range.Type, Type.Bool, expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type); } - ResolveExpression(e.Term, new ResolveOpts(opts, true)); + ResolveExpression(e.Term, opts); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(e.Term.Type, Type.Bool, expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type); // Since the body is more likely to infer the types of the bound variables, resolve it // first (above) and only then resolve the attributes (below). - ResolveAttributes(e.Attributes, new ResolveOpts(opts, true)); + ResolveAttributes(e.Attributes, opts); scope.PopMarker(); allTypeParameters.PopMarker(); expr.Type = Type.Bool; @@ -7920,7 +7914,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Term, opts); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression - ResolveAttributes(e.Attributes, new ResolveOpts(opts, true)); + ResolveAttributes(e.Attributes, opts); scope.PopMarker(); expr.Type = new SetType(e.Finite, e.Term.Type); @@ -7941,7 +7935,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Term, opts); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression - ResolveAttributes(e.Attributes, new ResolveOpts(opts, true)); + ResolveAttributes(e.Attributes, opts); scope.PopMarker(); expr.Type = new MapType(e.Finite, e.BoundVars[0].Type, e.Term.Type); @@ -7974,7 +7968,7 @@ namespace Microsoft.Dafny } foreach (var read in e.Reads) { - ResolveFrameExpression(read, true, false, opts.codeContext); + ResolveFrameExpression(read, true, opts.codeContext); } ResolveExpression(e.Term, opts); diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 9d4d67f1..49e6efa0 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -9,9 +9,9 @@ method GhostDivergentLoop() a[1] := -1; ghost var i := 0; while (i < 2) - decreases *; // error: not allowed on a ghost loop - invariant i <= 2; - invariant (forall j :: 0 <= j && j < i ==> a[j] > 0); + decreases * // error: not allowed on a ghost loop + invariant i <= 2 + invariant (forall j :: 0 <= j && j < i ==> a[j] > 0) { i := 0; } @@ -613,20 +613,7 @@ module GhostAllocationTests { p := new G; // error: ditto } - method GhostNew1(n: nat) - { - var a := new G[n]; - forall i | 0 <= i < n { - a[i] := new G; // error: 'new' is currently not supported in forall statements - } - forall i | 0 <= i < n - ensures true; // this makes the whole 'forall' statement into a ghost statement - { - a[i] := new G; // error: 'new' not allowed in ghost contexts, and proof-forall cannot update state - } - } - - method GhostNew2(n: nat, ghost g: int) returns (t: G, z: int) + method GhostNew1(n: nat, ghost g: int) returns (t: G, z: int) { if n < 0 { z, t := 5, new G; // fine @@ -636,14 +623,14 @@ module GhostAllocationTests { } } - method GhostNew3(ghost b: bool) + method GhostNew2(ghost b: bool) { if (b) { var y := new GIter(); // error: 'new' not allowed in ghost contexts (and a non-ghost method is not allowed to be called here either) } } - method GhostNew4(n: nat) + method GhostNew3(n: nat) { var g := new G; calc { @@ -653,12 +640,28 @@ module GhostAllocationTests { } } - ghost method GhostNew5(g: G) + ghost method GhostNew4(g: G) modifies g; { } } +module NewForall { + class G { } + method NewForallTest(n: nat) + { + var a := new G[n]; + forall i | 0 <= i < n { + a[i] := new G; // error: 'new' is currently not supported in forall statements + } + forall i | 0 <= i < n + ensures true; // this makes the whole 'forall' statement into a ghost statement + { + a[i] := new G; // error: 'new' not allowed in ghost contexts, and proof-forall cannot update state + } + } +} + // ------------------------- underspecified types ------------------------------ module UnderspecifiedTypes { @@ -706,7 +709,7 @@ module StatementsInExpressions { { assert 6 < 8; } { var x := 8; while x != 0 - decreases *; // error: cannot use 'decreases *' in a ghost context + decreases * // error: cannot use 'decreases *' here { x := x - 1; } @@ -739,7 +742,7 @@ module StatementsInExpressions { { assert 6 < 8; } { var x := 8; while x != 0 - decreases *; // error: cannot use 'decreases *' in a ghost context + decreases * // error: cannot use 'decreases *' here { x := x - 1; } @@ -852,40 +855,48 @@ class ModifyStatementClass { ghost method G0() modifies `g; modifies `x; // error: non-ghost field mentioned in ghost context - { - modify `g; - modify `x; // error: non-ghost field mentioned in ghost context - } - method G1() - modifies this; - { - modify `x; - if g < 100 { - // we are now in a ghost context +} +module ModifyStatementClass_More { + class C { + var x: int; + ghost var g: int; + ghost method G0() + modifies `g; + { + modify `g; modify `x; // error: non-ghost field mentioned in ghost context } - } - method G2(y: nat) - modifies this; - { - if g < 100 { - // we're now in a ghost context - var n := 0; - while n < y - modifies `x; // error: non-ghost field mentioned in ghost context - { - if * { - g := g + 1; // if we got as far as verification, this would be flagged as an error too - } - n := n + 1; + method G1() + modifies this; + { + modify `x; + if g < 100 { + // we are now in a ghost context + modify `x; // error: non-ghost field mentioned in ghost context } } - modify `x; // fine - ghost var i := 0; - while i < y - modifies `x; // error: non-ghost field mentioned in ghost context + method G2(y: nat) + modifies this; { - i := i + 1; + if g < 100 { + // we're now in a ghost context + var n := 0; + while n < y + modifies `x; // error: non-ghost field mentioned in ghost context + { + if * { + g := g + 1; // if we got as far as verification, this would be flagged as an error too + } + n := n + 1; + } + } + modify `x; // fine + ghost var i := 0; + while i < y + modifies `x; // error: non-ghost field mentioned in ghost context + { + i := i + 1; + } } } } @@ -1298,7 +1309,7 @@ module FrameTargetFields { modifies `z // cool { } - +} } module FrameTargetFields_More { class C { var x: int var y: int ghost var z: int method P() modifies this { @@ -1400,20 +1411,20 @@ module SuchThat { module GhostTests { class G { } - method GhostNew4(n: nat) + method GhostNew3(n: nat) { var g := new G; calc { 5; 2 + 3; - { if n != 0 { GhostNew4(n-1); } } // error: cannot call non-ghost method in a ghost context + { if n != 0 { GhostNew3(n-1); } } // error: cannot call non-ghost method in a ghost context 1 + 4; - { GhostNew5(g); } // error: cannot call method with nonempty modifies + { GhostNew4(g); } // error: cannot call method with nonempty modifies -5 + 10; } } - ghost method GhostNew5(g: G) + ghost method GhostNew4(g: G) modifies g; { } @@ -1524,7 +1535,7 @@ module EvenMoreGhostTests { ensures false; { while (true) - decreases *; // error: not allowed in ghost context + decreases * // error: not allowed here { } } @@ -1548,20 +1559,6 @@ module EvenMoreGhostTests { } } } - ghost method Bad() - { - var x: int; - calc { - 1; -//****** { x := 1; } // error: updates to locals defined outside of the hint are not allowed - x; - { - var x: int; - x := 1; // this is OK - } - 1; - } - } } module BadGhostTransfer { @@ -1619,3 +1616,79 @@ module UnderspecifiedTypedShouldBeResolvedOnlyOnce { } } } + +module LoopResolutionTests { + class C { + var x: int + ghost var y: int + } + + ghost method M(c: C) + requires c != null + modifies c + { + var n := 0; + while n < 100 + modifies c`y + modifies c`x // error: not allowed to mention non-ghost field in modifies clause of ghost loops + { + c.x := c.x + 1; // error: assignment to non-ghost field not allowed here + } + } + + method MM(c: C) + requires c != null + modifies c + { + var n := 0; + while + invariant n <= 100 + modifies c // regression test + { + case n < 100 => n := n + 1; + } + } + + method MMX(c: C, ghost g: int) + requires c != null + modifies c + { + var n := 0; + while + invariant n <= 100 + modifies c`y + modifies c`x // error: not allowed to mention non-ghost field in modifies clause of ghost loops + { + case n < 100 => n := n + 1; // error: cannot assign to non-ghost in a ghost loop + case g < 56 && n != 100 => n := n + 1; // error: cannot assign to non-ghost in a ghost loop + } + } + + method MD0(c: C, ghost g: nat) + requires c != null + modifies c + decreases * + { + var n := 0; + while n + g < 100 + invariant n <= 100 + decreases * // error: disallowed on ghost loops + { + n := n + 1; // error: cannot assign to non-ghost in a ghost loop + } + } + + method MD1(c: C, ghost g: nat) + requires c != null + modifies c + decreases * + { + var n := 0; + while + invariant n <= 100 + decreases * // error: disallowed on ghost loops + { + case n + g < 100 => n := n + 1; // error: cannot assign to non-ghost in a ghost loop + } + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index 6f4b3519..edf61b33 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -26,113 +26,126 @@ ResolutionErrors.dfy(599,25): Error: the type of this variable is underspecified ResolutionErrors.dfy(599,23): Error: type variable 'T' in the function call to 'P' could not be determined ResolutionErrors.dfy(612,13): Error: 'new' is not allowed in ghost contexts ResolutionErrors.dfy(613,9): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(620,14): Error: new allocation not supported in forall statements -ResolutionErrors.dfy(625,11): Error: the body of the enclosing forall statement is not allowed to update heap locations -ResolutionErrors.dfy(625,14): Error: new allocation not allowed in ghost context -ResolutionErrors.dfy(635,23): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(642,15): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(651,17): Error: 'new' is not allowed in ghost contexts -ResolutionErrors.dfy(669,21): Error: the type of this variable is underspecified -ResolutionErrors.dfy(709,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(742,22): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(773,19): Error: calls to methods with side-effects are not allowed inside a statement expression -ResolutionErrors.dfy(774,20): Error: wrong number of method result arguments (got 0, expected 1) -ResolutionErrors.dfy(786,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(796,4): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(807,36): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(816,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') -ResolutionErrors.dfy(830,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(831,6): Error: RHS (of type int) not assignable to LHS (of type object) -ResolutionErrors.dfy(832,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(837,6): Error: RHS (of type G) not assignable to LHS (of type object) -ResolutionErrors.dfy(838,6): Error: RHS (of type Dt) not assignable to LHS (of type object) -ResolutionErrors.dfy(839,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) -ResolutionErrors.dfy(901,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(902,4): Error: LHS of array assignment must denote an array element (found seq) -ResolutionErrors.dfy(907,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(908,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(909,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(910,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(911,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(912,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(993,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 -ResolutionErrors.dfy(994,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C -ResolutionErrors.dfy(1005,7): Error: Duplicate name of top-level declaration: BadSyn2 -ResolutionErrors.dfy(1002,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List -ResolutionErrors.dfy(1003,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1004,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1011,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A -ResolutionErrors.dfy(1014,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1018,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1027,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed -ResolutionErrors.dfy(1030,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1035,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A -ResolutionErrors.dfy(1054,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1061,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P -ResolutionErrors.dfy(1073,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1083,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1088,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1093,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1094,6): Error: RHS (of type P) not assignable to LHS (of type P) -ResolutionErrors.dfy(1099,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1100,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1101,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1124,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -ResolutionErrors.dfy(1126,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -ResolutionErrors.dfy(1231,26): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1232,31): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1233,29): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1243,34): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1259,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1260,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') -ResolutionErrors.dfy(1297,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) -ResolutionErrors.dfy(1307,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1335,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) -ResolutionErrors.dfy(1345,29): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1347,49): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1347,54): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1368,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1368,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1369,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1369,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1370,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1370,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) -ResolutionErrors.dfy(1371,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1371,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) -ResolutionErrors.dfy(1376,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1376,13): Error: arguments must have the same type (got int and #type) -ResolutionErrors.dfy(1377,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1377,13): Error: arguments must have the same type (got int and #module) -ResolutionErrors.dfy(1378,4): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1379,4): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1388,11): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1389,9): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1390,13): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1393,15): Error: type of RHS of let-such-that expression must be boolean (got int) -ResolutionErrors.dfy(1436,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1458,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1459,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1460,20): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1463,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(1445,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1458,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(1487,18): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1488,23): Error: a hint is not allowed to update heap locations -ResolutionErrors.dfy(1489,11): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1492,21): Error: a while statement used inside a hint is not allowed to have a modifies clause -ResolutionErrors.dfy(1480,24): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1487,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(1516,20): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1409,29): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(1411,17): Error: calls to methods with side-effects are not allowed inside a hint -ResolutionErrors.dfy(1527,16): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(1545,12): Error: trying to break out of more loop levels than there are enclosing loops -ResolutionErrors.dfy(1571,16): Error: ghost fields are allowed only in specification contexts -ResolutionErrors.dfy(1578,9): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1584,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost -ResolutionErrors.dfy(1601,8): Error: 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) -ResolutionErrors.dfy(1610,26): Error: ghost variables are allowed only in specification contexts -ResolutionErrors.dfy(1618,6): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(622,23): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(629,15): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(638,17): Error: 'new' is not allowed in ghost contexts +ResolutionErrors.dfy(655,14): Error: new allocation not supported in forall statements +ResolutionErrors.dfy(660,11): Error: the body of the enclosing forall statement is not allowed to update heap locations +ResolutionErrors.dfy(660,14): Error: new allocation not allowed in ghost context +ResolutionErrors.dfy(672,21): Error: the type of this variable is underspecified +ResolutionErrors.dfy(712,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(745,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(776,19): Error: calls to methods with side-effects are not allowed inside a statement expression +ResolutionErrors.dfy(777,20): Error: wrong number of method result arguments (got 0, expected 1) +ResolutionErrors.dfy(789,23): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(799,4): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(810,36): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(819,17): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ResolutionErrors.dfy(833,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(834,6): Error: RHS (of type int) not assignable to LHS (of type object) +ResolutionErrors.dfy(835,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(840,6): Error: RHS (of type G) not assignable to LHS (of type object) +ResolutionErrors.dfy(841,6): Error: RHS (of type Dt) not assignable to LHS (of type object) +ResolutionErrors.dfy(842,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) +ResolutionErrors.dfy(867,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(875,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(885,20): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(896,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(912,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(913,4): Error: LHS of array assignment must denote an array element (found seq) +ResolutionErrors.dfy(918,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(919,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(920,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(921,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(922,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(923,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(1004,11): Error: Wrong number of type arguments (2 instead of 1) passed to array type: array3 +ResolutionErrors.dfy(1005,11): Error: Wrong number of type arguments (2 instead of 1) passed to class: C +ResolutionErrors.dfy(1016,7): Error: Duplicate name of top-level declaration: BadSyn2 +ResolutionErrors.dfy(1013,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List +ResolutionErrors.dfy(1014,17): Error: Undeclared top-level type or type parameter: badName (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1015,22): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1022,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> A +ResolutionErrors.dfy(1025,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1029,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1038,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed +ResolutionErrors.dfy(1041,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1046,7): Error: Cycle among redirecting types (newtypes, type synonyms): A -> B -> A +ResolutionErrors.dfy(1065,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1072,35): Error: Wrong number of type arguments (2 instead of 1) passed to opaque type: P +ResolutionErrors.dfy(1084,13): Error: Undeclared top-level type or type parameter: BX (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1094,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1099,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1104,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1105,6): Error: RHS (of type P) not assignable to LHS (of type P) +ResolutionErrors.dfy(1110,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1111,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1112,13): Error: arguments must have the same type (got P and P) +ResolutionErrors.dfy(1135,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1137,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1242,26): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1243,31): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1244,29): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1254,34): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1270,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1271,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') +ResolutionErrors.dfy(1308,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) +ResolutionErrors.dfy(1318,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1346,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) +ResolutionErrors.dfy(1356,29): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1358,49): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1358,54): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1379,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1379,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1380,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1380,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1381,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1381,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #type, or a map with domain #type (instead got map) +ResolutionErrors.dfy(1382,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1382,13): Error: second argument to "in" must be a set, multiset, or sequence with elements of type #module, or a map with domain #module (instead got map) +ResolutionErrors.dfy(1387,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1387,13): Error: arguments must have the same type (got int and #type) +ResolutionErrors.dfy(1388,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1388,13): Error: arguments must have the same type (got int and #module) +ResolutionErrors.dfy(1389,4): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1390,4): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1399,11): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1400,9): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1401,13): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1404,15): Error: type of RHS of let-such-that expression must be boolean (got int) +ResolutionErrors.dfy(1447,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1469,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1470,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1471,20): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1474,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1456,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1469,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1498,18): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1499,23): Error: a hint is not allowed to update heap locations +ResolutionErrors.dfy(1500,11): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1503,21): Error: a while statement used inside a hint is not allowed to have a modifies clause +ResolutionErrors.dfy(1491,24): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1498,18): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1527,20): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1420,29): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(1422,17): Error: calls to methods with side-effects are not allowed inside a hint +ResolutionErrors.dfy(1538,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1556,12): Error: trying to break out of more loop levels than there are enclosing loops +ResolutionErrors.dfy(1568,16): Error: ghost fields are allowed only in specification contexts +ResolutionErrors.dfy(1575,9): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1581,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(1598,8): Error: 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) +ResolutionErrors.dfy(1607,26): Error: ghost variables are allowed only in specification contexts +ResolutionErrors.dfy(1615,6): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(1633,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1635,10): Error: Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1660,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1662,25): Error: 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) +ResolutionErrors.dfy(1663,35): Error: 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) +ResolutionErrors.dfy(1673,4): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1677,8): Error: 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) +ResolutionErrors.dfy(1687,4): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1691,29): Error: 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) ResolutionErrors.dfy(469,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -144,18 +157,14 @@ ResolutionErrors.dfy(475,14): Error: when allocating an object of type 'YHWH', o ResolutionErrors.dfy(480,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called ResolutionErrors.dfy(481,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called ResolutionErrors.dfy(483,9): Error: class Lamb does not have an anonymous constructor -ResolutionErrors.dfy(850,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) -ResolutionErrors.dfy(854,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(857,12): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(865,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(875,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(886,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1042,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1045,20): Error: unresolved identifier: x -ResolutionErrors.dfy(1048,23): Error: unresolved identifier: x -ResolutionErrors.dfy(1050,19): Error: unresolved identifier: x -ResolutionErrors.dfy(1052,19): Error: unresolved identifier: x -ResolutionErrors.dfy(12,16): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(853,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) +ResolutionErrors.dfy(857,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1053,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1056,20): Error: unresolved identifier: x +ResolutionErrors.dfy(1059,23): Error: unresolved identifier: x +ResolutionErrors.dfy(1061,19): Error: unresolved identifier: x +ResolutionErrors.dfy(1063,19): Error: unresolved identifier: x +ResolutionErrors.dfy(12,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(24,11): Error: array selection requires an array2 (got array3) ResolutionErrors.dfy(25,12): Error: sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got array3) ResolutionErrors.dfy(26,11): Error: array selection requires an array4 (got array) @@ -187,17 +196,17 @@ ResolutionErrors.dfy(416,10): Error: second argument to ==> must be of type bool ResolutionErrors.dfy(421,10): Error: first argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(421,10): Error: second argument to ==> must be of type bool (instead got int) ResolutionErrors.dfy(580,18): Error: unresolved identifier: w -ResolutionErrors.dfy(683,11): Error: lemmas are not allowed to have modifies clauses -ResolutionErrors.dfy(924,9): Error: unresolved identifier: s -ResolutionErrors.dfy(935,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) -ResolutionErrors.dfy(936,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) -ResolutionErrors.dfy(942,16): Error: condition is expected to be of type bool, but is int -ResolutionErrors.dfy(943,16): Error: member 3 does not exist in datatype _tuple#3 -ResolutionErrors.dfy(943,26): Error: member x does not exist in datatype _tuple#2 -ResolutionErrors.dfy(966,15): Error: arguments to / must have the same type (got real and int) -ResolutionErrors.dfy(967,10): Error: second argument to % must be of type int (instead got real) -ResolutionErrors.dfy(1112,8): Error: new cannot be applied to a trait -ResolutionErrors.dfy(1133,13): Error: first argument to / must be of numeric type (instead got set) -ResolutionErrors.dfy(1140,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1155,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -202 resolution/type errors detected in ResolutionErrors.dfy +ResolutionErrors.dfy(686,11): Error: lemmas are not allowed to have modifies clauses +ResolutionErrors.dfy(935,9): Error: unresolved identifier: s +ResolutionErrors.dfy(946,32): Error: RHS (of type (int,int,real)) not assignable to LHS (of type (int,real,int)) +ResolutionErrors.dfy(947,37): Error: RHS (of type (int,real,int)) not assignable to LHS (of type (int,real,int,real)) +ResolutionErrors.dfy(953,16): Error: condition is expected to be of type bool, but is int +ResolutionErrors.dfy(954,16): Error: member 3 does not exist in datatype _tuple#3 +ResolutionErrors.dfy(954,26): Error: member x does not exist in datatype _tuple#2 +ResolutionErrors.dfy(977,15): Error: arguments to / must have the same type (got real and int) +ResolutionErrors.dfy(978,10): Error: second argument to % must be of type int (instead got real) +ResolutionErrors.dfy(1123,8): Error: new cannot be applied to a trait +ResolutionErrors.dfy(1144,13): Error: first argument to / must be of numeric type (instead got set) +ResolutionErrors.dfy(1151,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1166,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +211 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 8a869bcfaeceb6b5a1d01e9b1c0c08b7000a094e Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 28 Sep 2015 22:47:35 -0700 Subject: Removed specContextOnly parameter from ResolveStatement. Moved all bounds discovery to resolution pass 1. --- Source/Dafny/Resolver.cs | 277 ++++++++++++++------------------ Test/dafny0/ResolutionErrors.dfy | 26 +-- Test/dafny0/ResolutionErrors.dfy.expect | 27 +++- Test/dafny4/Regression0.dfy | 6 +- Test/dafny4/Regression0.dfy.expect | 3 +- Test/dafny4/set-compr.dfy | 54 +++++-- Test/dafny4/set-compr.dfy.expect | 15 +- Test/hofs/ReadsReads.dfy | 4 +- 8 files changed, 218 insertions(+), 194 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index 9f2feb14..1c376c49 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -1336,11 +1336,6 @@ namespace Microsoft.Dafny // ---------------------------------- Pass 0 ---------------------------------- // This pass resolves names, introduces (and may solve) type constraints, and // builds the module's call graph. - // Some bounds are discovered during this pass [is this necessary? can they be - // moved to pass 1 like the other bounds discovery? --KRML], namely: - // - forall statements - // - quantifier expressions - // - map comprehensions // For 'newtype' declarations, it also checks that all types were fully // determined. // ---------------------------------------------------------------------------- @@ -1375,7 +1370,7 @@ namespace Microsoft.Dafny if (!CheckTypeInference_Visitor.IsDetermined(dd.BaseType.NormalizeExpand())) { reporter.Error(MessageSource.Resolver, dd.tok, "newtype's base type is not fully determined; add an explicit type for '{0}'", dd.Var.Name); } - CheckTypeInference(dd.Constraint); + CheckTypeInference(dd.Constraint, dd); scope.PopMarker(); } } @@ -1408,7 +1403,10 @@ namespace Microsoft.Dafny // * checks that type inference was able to determine all types // * fills in the .ResolvedOp field of binary expressions // * discovers bounds for: + // - forall statements // - set comprehensions + // - map comprehensions + // - quantifier expressions // - assign-such-that statements // - compilable let-such-that expressions // - newtype constraints @@ -1432,7 +1430,7 @@ namespace Microsoft.Dafny iter.SubExpressions.Iter(e => CheckExpression(e, this, iter)); } if (iter.Body != null) { - CheckTypeInference(iter.Body); + CheckTypeInference(iter.Body, iter); if (prevErrCnt == reporter.Count(ErrorLevel.Error)) { ComputeGhostInterest(iter.Body, false, iter); CheckExpression(iter.Body, this, iter); @@ -2047,22 +2045,22 @@ namespace Microsoft.Dafny private void CheckTypeInference_Member(MemberDecl member) { if (member is Method) { var m = (Method)member; - m.Req.Iter(CheckTypeInference_MaybeFreeExpression); - m.Ens.Iter(CheckTypeInference_MaybeFreeExpression); - CheckTypeInference_Specification_FrameExpr(m.Mod); - CheckTypeInference_Specification_Expr(m.Decreases); + m.Req.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m)); + m.Ens.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m)); + CheckTypeInference_Specification_FrameExpr(m.Mod, m); + CheckTypeInference_Specification_Expr(m.Decreases, m); if (m.Body != null) { - CheckTypeInference(m.Body); + CheckTypeInference(m.Body, m); } } else if (member is Function) { var f = (Function)member; var errorCount = reporter.Count(ErrorLevel.Error); - f.Req.Iter(CheckTypeInference); - f.Ens.Iter(CheckTypeInference); - f.Reads.Iter(fe => CheckTypeInference(fe.E)); - CheckTypeInference_Specification_Expr(f.Decreases); + f.Req.Iter(e => CheckTypeInference(e, f)); + f.Ens.Iter(e => CheckTypeInference(e, f)); + f.Reads.Iter(fe => CheckTypeInference(fe.E, f)); + CheckTypeInference_Specification_Expr(f.Decreases, f); if (f.Body != null) { - CheckTypeInference(f.Body); + CheckTypeInference(f.Body, f); } if (errorCount == reporter.Count(ErrorLevel.Error) && f is FixpointPredicate) { var cop = (FixpointPredicate)f; @@ -2071,43 +2069,51 @@ namespace Microsoft.Dafny } } - private void CheckTypeInference_MaybeFreeExpression(MaybeFreeExpression mfe) { + private void CheckTypeInference_MaybeFreeExpression(MaybeFreeExpression mfe, ICodeContext codeContext) { Contract.Requires(mfe != null); + Contract.Requires(codeContext != null); foreach (var e in Attributes.SubExpressions(mfe.Attributes)) { - CheckTypeInference(e); + CheckTypeInference(e, codeContext); } - CheckTypeInference(mfe.E); + CheckTypeInference(mfe.E, codeContext); } - private void CheckTypeInference_Specification_Expr(Specification spec) { + private void CheckTypeInference_Specification_Expr(Specification spec, ICodeContext codeContext) { Contract.Requires(spec != null); + Contract.Requires(codeContext != null); foreach (var e in Attributes.SubExpressions(spec.Attributes)) { - CheckTypeInference(e); + CheckTypeInference(e, codeContext); } - spec.Expressions.Iter(CheckTypeInference); + spec.Expressions.Iter(e => CheckTypeInference(e, codeContext)); } - private void CheckTypeInference_Specification_FrameExpr(Specification spec) { + private void CheckTypeInference_Specification_FrameExpr(Specification spec, ICodeContext codeContext) { Contract.Requires(spec != null); + Contract.Requires(codeContext != null); foreach (var e in Attributes.SubExpressions(spec.Attributes)) { - CheckTypeInference(e); + CheckTypeInference(e, codeContext); } - spec.Expressions.Iter(fe => CheckTypeInference(fe.E)); + spec.Expressions.Iter(fe => CheckTypeInference(fe.E, codeContext)); } - void CheckTypeInference(Expression expr) { + void CheckTypeInference(Expression expr, ICodeContext codeContext) { Contract.Requires(expr != null); + Contract.Requires(codeContext != null); PartiallySolveTypeConstraints(); - var c = new CheckTypeInference_Visitor(this); + var c = new CheckTypeInference_Visitor(this, codeContext); c.Visit(expr); } - void CheckTypeInference(Statement stmt) { + void CheckTypeInference(Statement stmt, ICodeContext codeContext) { Contract.Requires(stmt != null); - var c = new CheckTypeInference_Visitor(this); + Contract.Requires(codeContext != null); + var c = new CheckTypeInference_Visitor(this, codeContext); c.Visit(stmt); } class CheckTypeInference_Visitor : ResolverBottomUpVisitor { - public CheckTypeInference_Visitor(Resolver resolver) + readonly ICodeContext codeContext; + public CheckTypeInference_Visitor(Resolver resolver, ICodeContext codeContext) : base(resolver) { Contract.Requires(resolver != null); + Contract.Requires(codeContext != null); + this.codeContext = codeContext; } protected override void VisitOneStmt(Statement stmt) { if (stmt is VarDeclStmt) { @@ -2118,6 +2124,9 @@ namespace Microsoft.Dafny } else if (stmt is ForallStmt) { var s = (ForallStmt)stmt; s.BoundVars.Iter(bv => CheckTypeIsDetermined(bv.tok, bv.Type, "bound variable")); + List missingBounds; + s.Bounds = DiscoverBestBounds_MultipleVars(s.BoundVars, s.Range, true, true, out missingBounds); + } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; if (s.AssumeToken == null) { @@ -2154,27 +2163,55 @@ namespace Microsoft.Dafny resolver.reporter.Error(MessageSource.Resolver, bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", bv.Name); } } - if (e is SetComprehension) { - var sc = (SetComprehension)e; - if (sc.Finite) { - // A set must be finite. Discover bounds for the Range expression, but report an error only if the Term is not - // of a finite-individuals type. - List missingBounds; - sc.Bounds = DiscoverBestBounds_MultipleVars(sc.BoundVars, sc.Range, true, true, out missingBounds); - if (missingBounds.Count != 0) { - sc.MissingBounds = missingBounds; - if (sc.Type.HasFinitePossibleValues) { - // This means the set is finite, regardless of if the Range is bounded. So, we don't give any error here. - // However, if this expression is used in a non-ghost context (which is not yet known at this stage of - // resolution), the resolver will generate an error about that later. - } else { - foreach (var bv in sc.MissingBounds) { - resolver.reporter.Error(MessageSource.Resolver, sc, "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); - } + // apply bounds discovery to quantifiers, finite sets, and finite maps + string what = null; + Expression whereToLookForBounds = null; + bool polarity = true; + if (e is QuantifierExpr) { + what = "quantifier"; + whereToLookForBounds = ((QuantifierExpr)e).LogicalBody(); + polarity = e is ExistsExpr; + } else if (e is SetComprehension && ((SetComprehension)e).Finite) { + what = "set comprehension"; + whereToLookForBounds = e.Range; + } else if (e is MapComprehension && ((MapComprehension)e).Finite) { + what = "map comprehension"; + whereToLookForBounds = e.Range; + } + if (whereToLookForBounds != null) { + List missingBounds; + e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, whereToLookForBounds, polarity, true, out missingBounds); + if (missingBounds.Count != 0) { + e.MissingBounds = missingBounds; + + if ((e is SetComprehension && !((SetComprehension)e).Finite) || (e is MapComprehension && !((MapComprehension)e).Finite)) { + // a possibly infinite set/map has no restrictions on its range + } else if (e is QuantifierExpr) { + // don't report any errors at this time (instead, wait to see if the quantifier is used in a non-ghost context) + } else if (e is SetComprehension && e.Type.HasFinitePossibleValues) { + // This means the set is finite, regardless of if the Range is bounded. So, we don't give any error here. + // However, if this expression is used in a non-ghost context (which is not yet known at this stage of + // resolution), the resolver will generate an error about that later. + } else { + // we cannot be sure that the set/map really is finite + foreach (var bv in missingBounds) { + resolver.reporter.Error(MessageSource.Resolver, e, "a {0} must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{1}'", what, bv.Name); + } + } + } + if (codeContext is Function && e.Bounds != null) { + // functions are not allowed to depend on the set of allocated objects + Contract.Assert(e.Bounds.Count == e.BoundVars.Count); + for (int i = 0; i < e.Bounds.Count; i++) { + var bound = e.Bounds[i] as ComprehensionExpr.RefBoundedPool; + if (bound != null) { + var bv = e.BoundVars[i]; + resolver.reporter.Error(MessageSource.Resolver, expr, "a {0} involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{1}'", what, bv.Name); } } } } + } else if (expr is MemberSelectExpr) { var e = (MemberSelectExpr)expr; if (e.Member is Function || e.Member is Method) { @@ -4035,7 +4072,7 @@ namespace Microsoft.Dafny int prevErrors = reporter.Count(ErrorLevel.Error); ResolveExpression(arg, opts); if (prevErrors == reporter.Count(ErrorLevel.Error)) { - CheckTypeInference(arg); + CheckTypeInference(arg, opts.codeContext); } } } @@ -4289,7 +4326,7 @@ namespace Microsoft.Dafny scope.Push(k.Name, k); // we expect no name conflict for _k } var prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveBlockStatement(m.Body, m.IsGhost, m); + ResolveBlockStatement(m.Body, m); SolveAllTypeConstraints(); if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { //KRML ComputeGhostInterest(m.Body, m); @@ -4411,7 +4448,7 @@ namespace Microsoft.Dafny // Resolve body if (iter.Body != null) { - ResolveBlockStatement(iter.Body, false, iter); + ResolveBlockStatement(iter.Body, iter); if (reporter.Count(ErrorLevel.Error) == postSpecErrorCount) { //KRML ComputeGhostInterest(iter.Body, iter); } @@ -5249,11 +5286,7 @@ namespace Microsoft.Dafny return at; } - /// - /// "specContextOnly" means that the statement must be erasable, that is, it should be okay to omit it - /// at run time. That means it must not have any side effects on non-ghost variables, for example. - /// - public void ResolveStatement(Statement stmt, bool specContextOnly, ICodeContext codeContext) { + public void ResolveStatement(Statement stmt, ICodeContext codeContext) { Contract.Requires(stmt != null); Contract.Requires(codeContext != null); if (!(stmt is ForallStmt)) { // forall statements do their own attribute resolution below @@ -5328,13 +5361,13 @@ namespace Microsoft.Dafny } s.hiddenUpdate = new UpdateStmt(s.Tok, s.EndTok, formals, s.rhss, true); // resolving the update statement will check for return/yield statement specifics. - ResolveStatement(s.hiddenUpdate, specContextOnly, codeContext); + ResolveStatement(s.hiddenUpdate, codeContext); } } else {// this is a regular return/yield statement. s.hiddenUpdate = null; } } else if (stmt is ConcreteUpdateStatement) { - ResolveConcreteUpdateStmt((ConcreteUpdateStatement)stmt, specContextOnly, codeContext); + ResolveConcreteUpdateStmt((ConcreteUpdateStatement)stmt, codeContext); } else if (stmt is VarDeclStmt) { var s = (VarDeclStmt)stmt; // We have three cases. @@ -5370,7 +5403,7 @@ namespace Microsoft.Dafny lhs.Type = local.Type; } // resolve the whole thing - ResolveConcreteUpdateStmt(s.Update, specContextOnly, codeContext); + ResolveConcreteUpdateStmt(s.Update, codeContext); } // Add the locals to the scope foreach (var local in s.Locals) { @@ -5382,7 +5415,7 @@ namespace Microsoft.Dafny } // Resolve the AssignSuchThatStmt, if any if (s.Update is AssignSuchThatStmt) { - ResolveConcreteUpdateStmt(s.Update, specContextOnly, codeContext); + ResolveConcreteUpdateStmt(s.Update, codeContext); } // Update the VarDeclStmt's ghost status according to its components foreach (var local in s.Locals) @@ -5481,52 +5514,40 @@ namespace Microsoft.Dafny } else if (stmt is BlockStmt) { var s = (BlockStmt)stmt; scope.PushMarker(); - ResolveBlockStatement(s, specContextOnly, codeContext); + ResolveBlockStatement(s, codeContext); scope.PopMarker(); } else if (stmt is IfStmt) { IfStmt s = (IfStmt)stmt; - bool branchesAreSpecOnly = specContextOnly; if (s.Guard != null) { - int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Guard, new ResolveOpts(codeContext, true)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); - if (!specContextOnly && successfullyResolved) { - branchesAreSpecOnly = UsesSpecFeatures(s.Guard); - } } - ResolveStatement(s.Thn, branchesAreSpecOnly, codeContext); + ResolveStatement(s.Thn, codeContext); if (s.Els != null) { - ResolveStatement(s.Els, branchesAreSpecOnly, codeContext); + ResolveStatement(s.Els, codeContext); } } else if (stmt is AlternativeStmt) { var s = (AlternativeStmt)stmt; - ResolveAlternatives(s.Alternatives, specContextOnly, null, codeContext); + ResolveAlternatives(s.Alternatives, null, codeContext); } else if (stmt is WhileStmt) { WhileStmt s = (WhileStmt)stmt; - bool bodyMustBeSpecOnly = specContextOnly; var fvs = new HashSet(); if (s.Guard != null) { - int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Guard, new ResolveOpts(codeContext, true)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; Translator.ComputeFreeVariables(s.Guard, fvs); ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); - if (!specContextOnly && successfullyResolved) { - bodyMustBeSpecOnly = UsesSpecFeatures(s.Guard); - } } ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, fvs); if (s.Body != null) { loopStack.Add(s); // push - ResolveStatement(s.Body, bodyMustBeSpecOnly, codeContext); + ResolveStatement(s.Body, codeContext); loopStack.RemoveAt(loopStack.Count - 1); // pop } else { string text = "havoc {" + Util.Comma(", ", fvs, fv => fv.Name) + "};"; // always terminate with a semi-colon @@ -5535,7 +5556,7 @@ namespace Microsoft.Dafny } else if (stmt is AlternativeLoopStmt) { var s = (AlternativeLoopStmt)stmt; - ResolveAlternatives(s.Alternatives, specContextOnly, s, codeContext); + ResolveAlternatives(s.Alternatives, s, codeContext); ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, codeContext, null); } else if (stmt is ForallStmt) { @@ -5559,23 +5580,13 @@ namespace Microsoft.Dafny // first (above) and only then resolve the attributes (below). ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true)); - bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == reporter.Count(ErrorLevel.Error) && UsesSpecFeatures(s.Range)); - if (!bodyMustBeSpecOnly && prevErrorCount == reporter.Count(ErrorLevel.Error)) { - CheckTypeInference(s.Range); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - s.Bounds = DiscoverBestBounds_MultipleVars(s.BoundVars, s.Range, true, true, out missingBounds); - if (missingBounds.Count != 0) { - bodyMustBeSpecOnly = true; - } - } - if (s.Body != null) { // clear the labels for the duration of checking the body, because break statements are not allowed to leave a forall statement var prevLblStmts = labeledStatements; var prevLoopStack = loopStack; labeledStatements = new Scope(); loopStack = new List(); - ResolveStatement(s.Body, bodyMustBeSpecOnly, codeContext); + ResolveStatement(s.Body, codeContext); labeledStatements = prevLblStmts; loopStack = prevLoopStack; } @@ -5627,7 +5638,7 @@ namespace Microsoft.Dafny ResolveFrameExpression(fe, false, codeContext); } if (s.Body != null) { - ResolveBlockStatement(s.Body, specContextOnly, codeContext); + ResolveBlockStatement(s.Body, codeContext); } } else if (stmt is CalcStmt) { @@ -5658,7 +5669,7 @@ namespace Microsoft.Dafny labeledStatements = new Scope(); loopStack = new List(); foreach (var h in s.Hints) { - ResolveStatement(h, true, codeContext); + ResolveStatement(h, codeContext); } labeledStatements = prevLblStmts; loopStack = prevLoopStack; @@ -5675,13 +5686,13 @@ namespace Microsoft.Dafny Contract.Assert(prevErrorCount != reporter.Count(ErrorLevel.Error) || s.Steps.Count == s.Hints.Count); } else if (stmt is MatchStmt) { - ResolveMatchStmt(stmt, specContextOnly, codeContext); + ResolveMatchStmt(stmt, codeContext); } else if (stmt is SkeletonStatement) { var s = (SkeletonStatement)stmt; reporter.Error(MessageSource.Resolver, s.Tok, "skeleton statements are allowed only in refining methods"); // nevertheless, resolve the underlying statement; hey, why not if (s.S != null) { - ResolveStatement(s.S, specContextOnly, codeContext); + ResolveStatement(s.S, codeContext); } } else { Contract.Assert(false); throw new cce.UnreachableException(); @@ -5726,18 +5737,12 @@ namespace Microsoft.Dafny } } - void ResolveMatchStmt(Statement stmt, bool specContextOnly, ICodeContext codeContext) { + void ResolveMatchStmt(Statement stmt, ICodeContext codeContext) { MatchStmt s = (MatchStmt)stmt; DesugarMatchStmtWithTupleExpression(s); - bool bodyIsSpecOnly = specContextOnly; - int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Source, new ResolveOpts(codeContext, true)); Contract.Assert(s.Source.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; - if (!specContextOnly && successfullyResolved) { - bodyIsSpecOnly = UsesSpecFeatures(s.Source); - } UserDefinedType sourceType = null; DatatypeDecl dtd = null; if (s.Source.Type.IsDatatype) { @@ -5814,7 +5819,7 @@ namespace Microsoft.Dafny } } foreach (Statement ss in mc.Body) { - ResolveStatement(ss, bodyIsSpecOnly, codeContext); + ResolveStatement(ss, codeContext); } // substitute body to replace the case pat with v. This needs to happen // after the body is resolved so we can scope the bv correctly. @@ -5824,7 +5829,7 @@ namespace Microsoft.Dafny foreach (Statement ss in mc.Body) { Statement clone = cloner.CloneStmt(ss); // resolve it again since we just cloned it. - ResolveStatement(clone, bodyIsSpecOnly, codeContext); + ResolveStatement(clone, codeContext); list.Add(clone); } mc.UpdateBody(list); @@ -6242,7 +6247,7 @@ namespace Microsoft.Dafny reporter.Info(MessageSource.Resolver, loopStmt.Tok, s); } } - private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, bool specContextOnly, ICodeContext codeContext) { + private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, ICodeContext codeContext) { Contract.Requires(codeContext != null); // First, resolve all LHS's and expression-looking RHS's. @@ -6265,7 +6270,7 @@ namespace Microsoft.Dafny var suchThat = (AssignSuchThatStmt)s; // this is the other possible subclass ResolveAssignSuchThatStmt(suchThat, codeContext); } else { - ResolveUpdateStmt(update, specContextOnly, codeContext, errorCountBeforeCheckingLhs); + ResolveUpdateStmt(update, codeContext, errorCountBeforeCheckingLhs); } ResolveAttributes(s.Attributes, new ResolveOpts(codeContext, true)); } @@ -6274,7 +6279,7 @@ namespace Microsoft.Dafny /// errorCountBeforeCheckingLhs is passed in so that this method can determined if any resolution errors were found during /// LHS or RHS checking, because only if no errors were found is update.ResolvedStmt changed. /// - private void ResolveUpdateStmt(UpdateStmt update, bool specContextOnly, ICodeContext codeContext, int errorCountBeforeCheckingLhs) { + private void ResolveUpdateStmt(UpdateStmt update, ICodeContext codeContext, int errorCountBeforeCheckingLhs) { Contract.Requires(update != null); Contract.Requires(codeContext != null); IToken firstEffectfulRhs = null; @@ -6367,7 +6372,7 @@ namespace Microsoft.Dafny } foreach (var a in update.ResolvedStatements) { - ResolveStatement(a, specContextOnly, codeContext); + ResolveStatement(a, codeContext); } } @@ -6393,7 +6398,7 @@ namespace Microsoft.Dafny ConstrainTypes(s.Expr.Type, Type.Bool, s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type); } - void ResolveAlternatives(List alternatives, bool specContextOnly, AlternativeLoopStmt loopToCatchBreaks, ICodeContext codeContext) { + void ResolveAlternatives(List alternatives, AlternativeLoopStmt loopToCatchBreaks, ICodeContext codeContext) { Contract.Requires(alternatives != null); Contract.Requires(codeContext != null); @@ -6412,7 +6417,7 @@ namespace Microsoft.Dafny foreach (var alternative in alternatives) { scope.PushMarker(); foreach (Statement ss in alternative.Body) { - ResolveStatement(ss, specContextOnly, codeContext); + ResolveStatement(ss, codeContext); } scope.PopMarker(); } @@ -6541,7 +6546,7 @@ namespace Microsoft.Dafny } } - void ResolveBlockStatement(BlockStmt blockStmt, bool specContextOnly, ICodeContext codeContext) { + void ResolveBlockStatement(BlockStmt blockStmt, ICodeContext codeContext) { Contract.Requires(blockStmt != null); Contract.Requires(codeContext != null); @@ -6561,7 +6566,7 @@ namespace Microsoft.Dafny Contract.Assert(r == Scope.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed } } - ResolveStatement(ss, specContextOnly, codeContext); + ResolveStatement(ss, codeContext); labeledStatements.PopMarker(); } } @@ -7878,25 +7883,6 @@ namespace Microsoft.Dafny allTypeParameters.PopMarker(); expr.Type = Type.Bool; - if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { - CheckTypeInference(e.LogicalBody()); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.LogicalBody(), e is ExistsExpr, true, out missingBounds); - if (missingBounds.Count != 0) { - e.MissingBounds = missingBounds; - } - if (opts.codeContext is Function && e.Bounds != null) { - Contract.Assert(e.Bounds.Count == e.BoundVars.Count); - for (int i = 0; i < e.Bounds.Count; i++) { - var bound = e.Bounds[i] as ComprehensionExpr.RefBoundedPool; - if (bound != null) { - var bv = e.BoundVars[i]; - reporter.Error(MessageSource.Resolver, expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name); - } - } - } - } - } else if (expr is SetComprehension) { var e = (SetComprehension)expr; int prevErrorCount = reporter.Count(ErrorLevel.Error); @@ -7936,19 +7922,6 @@ namespace Microsoft.Dafny scope.PopMarker(); expr.Type = new MapType(e.Finite, e.BoundVars[0].Type, e.Term.Type); - if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { - CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds - List missingBounds; - e.Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars, e.Range, true, true, out missingBounds); - if (missingBounds.Count != 0) { - e.MissingBounds = missingBounds; - if (e.Finite) { - foreach (var bv in e.MissingBounds) { - reporter.Error(MessageSource.Resolver, expr, "a map comprehension must produce a finite domain, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - } - } - } } else if (expr is LambdaExpr) { var e = (LambdaExpr)expr; int prevErrorCount = reporter.Count(ErrorLevel.Error); @@ -7977,7 +7950,7 @@ namespace Microsoft.Dafny } else if (expr is StmtExpr) { var e = (StmtExpr)expr; int prevErrorCount = reporter.Count(ErrorLevel.Error); - ResolveStatement(e.S, true, opts.codeContext); + ResolveStatement(e.S, opts.codeContext); if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var r = e.S as UpdateStmt; if (r != null && r.ResolvedStatements.Count == 1) { @@ -10335,21 +10308,19 @@ namespace Microsoft.Dafny } } else if (expr is NamedExpr) { return moduleInfo.IsAbstract ? false : UsesSpecFeatures(((NamedExpr)expr).Body); - } else if (expr is ComprehensionExpr) { - var q = expr as QuantifierExpr; - Contract.Assert(q == null || q.SplitQuantifier == null); // No split quantifiers during resolution - if (q != null && q.Bounds.Contains(null)) { - return true; // the quantifier cannot be compiled if the resolver found no bounds - } - return Contract.Exists(expr.SubExpressions, se => UsesSpecFeatures(se)); + } else if (expr is QuantifierExpr) { + var e = (QuantifierExpr)expr; + Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution + return e.UncompilableBoundVars().Count != 0; } else if (expr is SetComprehension) { var e = (SetComprehension)expr; - return (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term)); + return !e.Finite || e.UncompilableBoundVars().Count != 0 || (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term)); } else if (expr is MapComprehension) { var e = (MapComprehension)expr; - return (UsesSpecFeatures(e.Range)) || (UsesSpecFeatures(e.Term)); + return !e.Finite || e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.Range) || UsesSpecFeatures(e.Term); } else if (expr is LambdaExpr) { - return Contract.Exists(expr.SubExpressions, UsesSpecFeatures); + var e = (LambdaExpr)expr; + return UsesSpecFeatures(e.Term); } else if (expr is WildcardExpr) { return false; } else if (expr is StmtExpr) { diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 49e6efa0..e935c83d 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -586,16 +586,16 @@ method LetSuchThat(ghost z: int, n: nat) module NonInferredType { predicate P(x: T) - method NonInferredType0(x: int) + method InferredType(x: int) { var t; - assume forall z :: P(z) && z == t; // It would be nice to allow the following example, but the implementation calls DiscoverBounds before CheckInference for quantifiers. + assume forall z :: P(z) && z == t; assume t == x; // this statement determines the type of t and z } - method NonInferredType1(x: int) + method NonInferredType(x: int) { - var t; + var t; // error: the type of t is not determined assume forall z :: P(z) && z == t; // error: the type of z is not determined } } @@ -1126,15 +1126,15 @@ method TraitSynonym() // ----- set comprehensions where the term type is finite ----- module ObjectSetComprehensions { - // allowed in non-ghost context: - function A() : set { set o : object | true :: o } + // the following set comprehensions are known to be finite + function A() : set { set o : object | true :: o } // error: a function is not allowed to depend on the allocated state - lemma B() { var x := set o : object | true :: o; } + function method B() : set { set o : object | true :: o } // error: a function is not allowed to depend on the allocated state - // not allowed in non-ghost context: - function method C() : set { set o : object | true :: o } + // outside functions, the comprehension is permitted, but it cannot be compiled + lemma C() { var x := set o : object | true :: o; } - method D() { var x := set o : object | true :: o; } + method D() { var x := set o : object | true :: o; } // error: not (easily) compilable } // ------ regression test for type checking of integer division ----- @@ -1228,9 +1228,9 @@ module NonInferredTypeVariables { method BadClient(n: nat) { var p := P(n); // error: cannot infer the type argument for P - ghost var q := Q(n); // error: cannot infer the type argument for Q + ghost var q := Q(n); // error: cannot infer the type argument for Q (and thus q's type cannot be determined either) M(n); // error: cannot infer the type argument for M - var x := N(n); // error: cannot infer the type argument for N + var x := N(n); // error: cannot infer the type argument for N (and thus x's type cannot be determined either) var a := new array; // error: cannot infer the type argument for 'array' var c := new C; // error: cannot infer the type argument for 'C' var s: set; // type argument for 'set' @@ -1248,7 +1248,7 @@ module NonInferredTypeVariables { ghost var d0 := forall s :: s == {7} ==> s != {}; var d1 := forall s: set :: s in S ==> s == {}; var ggcc0: C; - var ggcc1: C; + var ggcc1: C; // error: full type cannot be determined ghost var d2 := forall c: C :: c != null ==> c.f == 10; ghost var d2' := forall c :: c == ggcc0 && c != null ==> c.f == 10; ghost var d2'' := forall c :: c == ggcc1 && c != null ==> c.f == c.f; // error: here, type of c is not determined diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index edf61b33..be19eeac 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -20,10 +20,9 @@ ResolutionErrors.dfy(535,7): Error: RHS (of type List) not assignable to LHS ResolutionErrors.dfy(540,7): Error: RHS (of type List) not assignable to LHS (of type List) ResolutionErrors.dfy(554,23): Error: type of case bodies do not agree (found Tree<_T1,_T0>, previous types Tree<_T0,_T1>) ResolutionErrors.dfy(566,24): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree -ResolutionErrors.dfy(592,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(592,23): Error: type variable 'T' in the function call to 'P' could not be determined -ResolutionErrors.dfy(599,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(598,8): Error: the type of this local variable is underspecified ResolutionErrors.dfy(599,23): Error: type variable 'T' in the function call to 'P' could not be determined +ResolutionErrors.dfy(599,18): Error: type of bound variable 'z' could not be determined; please specify the type explicitly ResolutionErrors.dfy(612,13): Error: 'new' is not allowed in ghost contexts ResolutionErrors.dfy(613,9): Error: 'new' is not allowed in ghost contexts ResolutionErrors.dfy(622,23): Error: 'new' is not allowed in ghost contexts @@ -81,12 +80,28 @@ ResolutionErrors.dfy(1105,6): Error: RHS (of type P) not assignable to LHS ResolutionErrors.dfy(1110,13): Error: arguments must have the same type (got P and P) ResolutionErrors.dfy(1111,13): Error: arguments must have the same type (got P and P) ResolutionErrors.dfy(1112,13): Error: arguments must have the same type (got P and P) -ResolutionErrors.dfy(1135,38): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1130,31): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +ResolutionErrors.dfy(1132,38): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' ResolutionErrors.dfy(1137,24): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1230,13): Error: type variable 'PT' in the function call to 'P' could not be determined +ResolutionErrors.dfy(1231,14): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1231,19): Error: type variable 'QT' in the function call to 'Q' could not be determined +ResolutionErrors.dfy(1232,4): Error: type '?' to the method 'M' is not determined +ResolutionErrors.dfy(1233,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1233,13): Error: type '?' to the method 'N' is not determined +ResolutionErrors.dfy(1234,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1235,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1236,8): Error: the type of this local variable is underspecified +ResolutionErrors.dfy(1237,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1238,8): Error: the type of this local variable is underspecified ResolutionErrors.dfy(1242,26): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1242,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly ResolutionErrors.dfy(1243,31): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1243,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly ResolutionErrors.dfy(1244,29): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1254,34): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1244,21): Error: type of bound variable 'c' could not be determined; please specify the type explicitly +ResolutionErrors.dfy(1251,8): Error: the type of this local variable is underspecified +ResolutionErrors.dfy(1254,29): Error: type of bound variable 'c' could not be determined; please specify the type explicitly ResolutionErrors.dfy(1270,21): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') ResolutionErrors.dfy(1271,24): Error: Undeclared top-level type or type parameter: X (did you forget to qualify a name or declare a module import 'opened?') ResolutionErrors.dfy(1308,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) @@ -209,4 +224,4 @@ ResolutionErrors.dfy(1123,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1144,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1151,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1166,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -211 resolution/type errors detected in ResolutionErrors.dfy +226 resolution/type errors detected in ResolutionErrors.dfy diff --git a/Test/dafny4/Regression0.dfy b/Test/dafny4/Regression0.dfy index be092261..666d9575 100644 --- a/Test/dafny4/Regression0.dfy +++ b/Test/dafny4/Regression0.dfy @@ -4,10 +4,10 @@ // This once crashed Dafny method M() { - var s := [1, "2"]; + var s := [1, "2"]; // error: all elements must have the same type if * { - assert exists n :: n in s && n != 1; + assert exists n :: n in s && n != 1; // the type of n is inferred to be int } else { - assert "2" in s; + assert "2" in s; // error: since the type of s wasn't determined } } diff --git a/Test/dafny4/Regression0.dfy.expect b/Test/dafny4/Regression0.dfy.expect index 9d1e3019..566b3e3f 100644 --- a/Test/dafny4/Regression0.dfy.expect +++ b/Test/dafny4/Regression0.dfy.expect @@ -1,4 +1,3 @@ Regression0.dfy(7,15): Error: All elements of display must be of the same type (got string, but type of previous elements is int) -Regression0.dfy(9,28): Error: the type of this variable is underspecified Regression0.dfy(11,15): Error: second argument to "in" must be a set, multiset, or sequence with elements of type string, or a map with domain string (instead got ?) -3 resolution/type errors detected in Regression0.dfy +2 resolution/type errors detected in Regression0.dfy diff --git a/Test/dafny4/set-compr.dfy b/Test/dafny4/set-compr.dfy index 71a07f3d..d093a924 100644 --- a/Test/dafny4/set-compr.dfy +++ b/Test/dafny4/set-compr.dfy @@ -22,7 +22,7 @@ method O() returns (ghost p: set) method P() returns (p: set) { - p := set o: object | true; // not allowed -- not in a ghost context + p := set o: object | true; // error: not (easily) compilable } ghost method Q() returns (p: set) @@ -30,26 +30,54 @@ ghost method Q() returns (p: set) p := set o: object | true; // allowed, since the whole method is ghost } -function F(): int +function F(p: object): int + requires p in set o: object | true // error: function is not allowed to depend on allocation state + ensures p in set o: object | true // error: ditto (although one could argue that this would be okay) + reads set o: object | true // error: same as for 'requires' + decreases set o: object | true // error: same as for 'ensures' +{ + if p in set o: object | true then // error: function is not allowed to depend on allocation state + F(p) + else + 0 +} + +function method G(p: object): int + requires p in set o: object | true // error (see F) + ensures p in set o: object | true // error (see F) + reads set o: object | true // error (see F) + decreases set o: object | true // error (see F) +{ + if p in set o: object | true then // error (see F) + G(p) + else + 0 +} + +method M0() returns (ghost r: int, s: int) requires null in set o: object | true // allowed ensures null in set o: object | true // allowed - reads set o: object | true // allowed + modifies set o: object | true // allowed decreases set o: object | true // allowed { - if null in set o: object | true then // allowed -- in a ghost context - F() - else - 0 + if null in set o: object | true { // this makes the "if" a ghost + r := G(null); + s := G(null); // error: assignment of non-ghost not allowed inside ghost "if" + } else { + r := 0; + } } -function method G(): int +method M1() returns (ghost r: int, s: int) requires null in set o: object | true // (X) allowed ensures null in set o: object | true // (X) allowed - reads set o: object | true // allowed + modifies set o: object | true // allowed decreases set o: object | true // (X) allowed { - if null in set o: object | true then // not allowed, since this is not a ghost context - G() - else - 0 + if null in set o: object | true { // this makes the "if" a ghost + r := G(null); + s := G(null); // error: assignment of non-ghost not allowed inside ghost "if" + } else { + r := 0; + } } diff --git a/Test/dafny4/set-compr.dfy.expect b/Test/dafny4/set-compr.dfy.expect index 615ee2bc..b0490a11 100644 --- a/Test/dafny4/set-compr.dfy.expect +++ b/Test/dafny4/set-compr.dfy.expect @@ -1,3 +1,14 @@ set-compr.dfy(25,7): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -set-compr.dfy(51,13): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -2 resolution/type errors detected in set-compr.dfy +set-compr.dfy(34,16): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(35,15): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(36,8): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(37,12): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(39,10): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(46,16): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(47,15): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(48,8): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(49,12): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(51,10): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'o' +set-compr.dfy(65,6): Error: 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) +set-compr.dfy(79,6): Error: 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) +13 resolution/type errors detected in set-compr.dfy diff --git a/Test/hofs/ReadsReads.dfy b/Test/hofs/ReadsReads.dfy index a6f8d922..60ac35f5 100644 --- a/Test/hofs/ReadsReads.dfy +++ b/Test/hofs/ReadsReads.dfy @@ -105,14 +105,14 @@ module WhatWeKnowAboutReads { module ReadsAll { function A(f: int -> int) : int - reads set o,x | o in f.reads(x) :: o + reads set x,o | o in f.reads(x) :: o // note, with "set o,x ..." instead, Dafny complains (this is perhaps less than ideal) requires forall x :: f.requires(x) { f(0) + f(1) + f(2) } function method B(f: int -> int) : int - reads set o,x | o in f.reads(x) :: o + reads set x,o | o in f.reads(x) :: o // note, with "set o,x ..." instead, Dafny complains (this is perhaps less than ideal) requires forall x :: f.requires(x) { f(0) + f(1) + f(2) -- cgit v1.2.3 From 27120ddc7adb3a0c789c1ee784d73a4be08de118 Mon Sep 17 00:00:00 2001 From: leino Date: Mon, 5 Oct 2015 08:59:16 -0700 Subject: Implemented resolution, verification, and (poorly performing) compilation of existential if guards. Fixed bugs in ghost checks involving comprehensions and attributes. Added SubstituteBoundedPool method. --- Source/Dafny/Compiler.cs | 40 +++-- Source/Dafny/DafnyAst.cs | 13 +- Source/Dafny/Resolver.cs | 49 +++--- Source/Dafny/Translator.cs | 139 +++++++++++++++-- Test/dafny0/Compilation.dfy | 35 ++++- Test/dafny0/Compilation.dfy.expect | 13 +- Test/dafny0/ExistentialGuards.dfy | 86 ++++++++++- Test/dafny0/ExistentialGuards.dfy.expect | 111 ++++++++++++-- Test/dafny0/ExistentialGuardsResolution.dfy | 154 +++++++++++++++++++ Test/dafny0/ExistentialGuardsResolution.dfy.expect | 167 +++++++++++++++++++++ Test/dafny0/ResolutionErrors.dfy | 20 +++ Test/dafny0/ResolutionErrors.dfy.expect | 7 +- 12 files changed, 769 insertions(+), 65 deletions(-) create mode 100644 Test/dafny0/ExistentialGuardsResolution.dfy create mode 100644 Test/dafny0/ExistentialGuardsResolution.dfy.expect (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs index 13381cc7..aa4ca3ec 100644 --- a/Source/Dafny/Compiler.cs +++ b/Source/Dafny/Compiler.cs @@ -1455,10 +1455,17 @@ namespace Microsoft.Dafny { } } else { Indent(indent); wr.Write("if ("); - TrExpr(s.Guard); + TrExpr(s.IsExistentialGuard ? Translator.AlphaRename((ExistsExpr)s.Guard, "eg_d", new Translator(null)) : s.Guard); wr.WriteLine(")"); - TrStmt(s.Thn, indent); + // We'd like to do "TrStmt(s.Thn, indent)", except we want the scope of any existential variables to come inside the block + Indent(indent); wr.WriteLine("{"); + if (s.IsExistentialGuard) { + IntroduceAndAssignBoundVars(indent + IndentAmount, (ExistsExpr)s.Guard); + } + TrStmtList(s.Thn.Body, indent); + Indent(indent); wr.WriteLine("}"); + if (s.Els != null) { Indent(indent); wr.WriteLine("else"); TrStmt(s.Els, indent); @@ -1467,13 +1474,14 @@ namespace Microsoft.Dafny { } else if (stmt is AlternativeStmt) { var s = (AlternativeStmt)stmt; - foreach (var alternative in s.Alternatives) { - } Indent(indent); foreach (var alternative in s.Alternatives) { wr.Write("if ("); - TrExpr(alternative.Guard); + TrExpr(alternative.IsExistentialGuard ? Translator.AlphaRename((ExistsExpr)alternative.Guard, "eg_d", new Translator(null)) : alternative.Guard); wr.WriteLine(") {"); + if (alternative.IsExistentialGuard) { + IntroduceAndAssignBoundVars(indent + IndentAmount, (ExistsExpr)alternative.Guard); + } TrStmtList(alternative.Body, indent); Indent(indent); wr.Write("} else "); @@ -1766,6 +1774,18 @@ namespace Microsoft.Dafny { } } + private void IntroduceAndAssignBoundVars(int indent, ExistsExpr exists) { + Contract.Requires(0 <= indent); + Contract.Requires(exists != null); + Contract.Assume(exists.Bounds != null); // follows from successful resolution + Contract.Assert(exists.Range == null); // follows from invariant of class IfStmt + foreach (var bv in exists.BoundVars) { + TrLocalVar(bv, false, indent); + } + var ivars = exists.BoundVars.ConvertAll(bv => (IVariable)bv); + TrAssignSuchThat(indent, ivars, exists.Term, exists.Bounds, exists.tok.line); + } + private void TrAssignSuchThat(int indent, List lhss, Expression constraint, List bounds, int debuginfoLine) { Contract.Requires(0 <= indent); Contract.Requires(lhss != null); @@ -2155,18 +2175,18 @@ namespace Microsoft.Dafny { } } - void TrLocalVar(LocalVariable s, bool alwaysInitialize, int indent) { - Contract.Requires(s != null); - if (s.IsGhost) { + void TrLocalVar(IVariable v, bool alwaysInitialize, int indent) { + Contract.Requires(v != null); + if (v.IsGhost) { // only emit non-ghosts (we get here only for local variables introduced implicitly by call statements) return; } Indent(indent); - wr.Write("{0} @{1}", TypeName(s.Type), s.CompileName); + wr.Write("{0} @{1}", TypeName(v.Type), v.CompileName); if (alwaysInitialize) { // produce a default value - wr.WriteLine(" = {0};", DefaultValue(s.Type)); + wr.WriteLine(" = {0};", DefaultValue(v.Type)); } else { wr.WriteLine(";"); } diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs index 64af1425..667f8407 100644 --- a/Source/Dafny/DafnyAst.cs +++ b/Source/Dafny/DafnyAst.cs @@ -3903,7 +3903,7 @@ namespace Microsoft.Dafny { Contract.Invariant(Expr != null); } - public ExprRhs(Expression expr, Attributes attrs = null) + public ExprRhs(Expression expr, Attributes attrs = null) // TODO: these 'attrs' apparently aren't handled correctly in the Cloner, and perhaps not in various visitors either (for example, CheckIsCompilable should not go into attributes) : base(expr.tok, attrs) { Contract.Requires(expr != null); @@ -7175,9 +7175,16 @@ namespace Microsoft.Dafny { public override IEnumerable SubExpressions { get { if (SplitQuantifier == null) { - return base.SubExpressions; + foreach (var e in base.SubExpressions) { + yield return e; + } } else { - return SplitQuantifier; + foreach (var e in Attributes.SubExpressions(Attributes)) { + yield return e; + } + foreach (var e in SplitQuantifier) { + yield return e; + } } } } diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index bc94e491..1798243c 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -2264,12 +2264,14 @@ namespace Microsoft.Dafny what = "quantifier"; whereToLookForBounds = ((QuantifierExpr)e).LogicalBody(); polarity = e is ExistsExpr; - } else if (e is SetComprehension && ((SetComprehension)e).Finite) { + } else if (e is SetComprehension) { what = "set comprehension"; whereToLookForBounds = e.Range; - } else if (e is MapComprehension && ((MapComprehension)e).Finite) { + } else if (e is MapComprehension) { what = "map comprehension"; whereToLookForBounds = e.Range; + } else { + Contract.Assume(e is LambdaExpr); // otherwise, unexpected ComprehensionExpr } if (whereToLookForBounds != null) { List missingBounds; @@ -2278,9 +2280,9 @@ namespace Microsoft.Dafny e.MissingBounds = missingBounds; if ((e is SetComprehension && !((SetComprehension)e).Finite) || (e is MapComprehension && !((MapComprehension)e).Finite)) { - // a possibly infinite set/map has no restrictions on its range + // a possibly infinite set/map has no restrictions on its range (unless it's used in a compilable context, which is checked later) } else if (e is QuantifierExpr) { - // don't report any errors at this time (instead, wait to see if the quantifier is used in a non-ghost context) + // a quantifier has no restrictions on its range (unless it's used in a compilable context, which is checked later) } else if (e is SetComprehension && e.Type.HasFinitePossibleValues) { // This means the set is finite, regardless of if the Range is bounded. So, we don't give any error here. // However, if this expression is used in a non-ghost context (which is not yet known at this stage of @@ -2341,7 +2343,6 @@ namespace Microsoft.Dafny var bin = expr as BinaryExpr; if (bin != null) { bin.ResolvedOp = ResolveOp(bin.Op, bin.E1.Type); - } } } @@ -5647,7 +5648,17 @@ namespace Microsoft.Dafny Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression ConstrainTypes(s.Guard.Type, Type.Bool, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); } - ResolveStatement(s.Thn, codeContext); + + scope.PushMarker(); + if (s.IsExistentialGuard) { + var exists = (ExistsExpr)s.Guard; + foreach (var v in exists.BoundVars) { + ScopePushAndReport(scope, v, "bound-variable"); + } + } + ResolveBlockStatement(s.Thn, codeContext); + scope.PopMarker(); + if (s.Els != null) { ResolveStatement(s.Els, codeContext); } @@ -6525,7 +6536,7 @@ namespace Microsoft.Dafny Contract.Requires(alternatives != null); Contract.Requires(codeContext != null); - // first, resolve the guards, which tells us whether or not the entire statement is a ghost statement + // first, resolve the guards foreach (var alternative in alternatives) { int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true)); @@ -6539,6 +6550,12 @@ namespace Microsoft.Dafny } foreach (var alternative in alternatives) { scope.PushMarker(); + if (alternative.IsExistentialGuard) { + var exists = (ExistsExpr)alternative.Guard; + foreach (var v in exists.BoundVars) { + ScopePushAndReport(scope, v, "bound-variable"); + } + } foreach (Statement ss in alternative.Body) { ResolveStatement(ss, codeContext); } @@ -9508,9 +9525,9 @@ namespace Microsoft.Dafny if (uncompilableBoundVars.Count != 0) { string what; if (e is SetComprehension) { - what = "set comprehensions"; + what = ((SetComprehension)e).Finite ? "set comprehensions" : "iset comprehensions"; } else if (e is MapComprehension) { - what = "map comprehensions"; + what = ((MapComprehension)e).Finite ? "map comprehensions" : "imap comprehensions"; } else { Contract.Assume(e is QuantifierExpr); // otherwise, unexpected ComprehensionExpr (since LambdaExpr is handled separately above) Contract.Assert(((QuantifierExpr)e).SplitQuantifier == null); // No split quantifiers during resolution @@ -9521,15 +9538,11 @@ namespace Microsoft.Dafny } return; } + // don't recurse down any attributes + if (e.Range != null) { CheckIsCompilable(e.Range); } + CheckIsCompilable(e.Term); + return; - } else if (expr is MapComprehension) { - var e = (MapComprehension)expr; - if (e.MissingBounds != null && !e.Finite) { - foreach (var bv in e.MissingBounds) { - reporter.Error(MessageSource.Resolver, expr, "imaps in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); - } - return; - } } else if (expr is NamedExpr) { if (!moduleInfo.IsAbstract) CheckIsCompilable(((NamedExpr)expr).Body); @@ -10436,7 +10449,7 @@ namespace Microsoft.Dafny } else if (expr is QuantifierExpr) { var e = (QuantifierExpr)expr; Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution - return e.UncompilableBoundVars().Count != 0; + return e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.LogicalBody()); } else if (expr is SetComprehension) { var e = (SetComprehension)expr; return !e.Finite || e.UncompilableBoundVars().Count != 0 || (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term)); diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs index c84f0cec..18b50686 100644 --- a/Source/Dafny/Translator.cs +++ b/Source/Dafny/Translator.cs @@ -4740,7 +4740,7 @@ namespace Microsoft.Dafny { var typeMap = Util.Dict(e.TypeArgs, Map(typeArgumentCopies, tp => (Type)new UserDefinedType(tp))); var newLocals = Map(typeArgumentCopies, tp => new Bpl.LocalVariable(tp.tok, new TypedIdent(tp.tok, nameTypeParam(tp), predef.Ty))); locals.AddRange(newLocals); - // Create local variables corresponding to the in-parameters: + // Create local variables corresponding to the bound variables: var substMap = SetupBoundVarsAsLocals(e.BoundVars, builder, locals, etran, typeMap); // Get the body of the quantifier and suitably substitute for the type variables and bound variables var body = Substitute(e.LogicalBody(true), null, substMap, typeMap); @@ -7244,24 +7244,30 @@ namespace Microsoft.Dafny { } else if (stmt is IfStmt) { AddComment(builder, stmt, "if statement"); IfStmt s = (IfStmt)stmt; - Bpl.Expr guard; + Expression guard; if (s.Guard == null) { guard = null; } else { - TrStmt_CheckWellformed(s.Guard, builder, locals, etran, true); - guard = etran.TrExpr(s.Guard); + guard = s.IsExistentialGuard ? AlphaRename((ExistsExpr)s.Guard, "eg$", this) : s.Guard; + TrStmt_CheckWellformed(guard, builder, locals, etran, true); } Bpl.StmtListBuilder b = new Bpl.StmtListBuilder(); CurrentIdGenerator.Push(); + if (s.IsExistentialGuard) { + var exists = (ExistsExpr)s.Guard; // the original (that is, not alpha-renamed) guard + IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran); + } Bpl.StmtList thn = TrStmt2StmtList(b, s.Thn, locals, etran); CurrentIdGenerator.Pop(); Bpl.StmtList els; Bpl.IfCmd elsIf = null; + b = new Bpl.StmtListBuilder(); + if (s.IsExistentialGuard) { + b.Add(new Bpl.AssumeCmd(guard.tok, Bpl.Expr.Not(etran.TrExpr(guard)))); + } if (s.Els == null) { - b = new Bpl.StmtListBuilder(); els = b.Collect(s.Tok); } else { - b = new Bpl.StmtListBuilder(); els = TrStmt2StmtList(b, s.Els, locals, etran); if (els.BigBlocks.Count == 1) { Bpl.BigBlock bb = els.BigBlocks[0]; @@ -7271,7 +7277,7 @@ namespace Microsoft.Dafny { } } } - builder.Add(new Bpl.IfCmd(stmt.Tok, guard, thn, elsIf, els)); + builder.Add(new Bpl.IfCmd(stmt.Tok, guard == null || s.IsExistentialGuard ? null : etran.TrExpr(guard), thn, elsIf, els)); } else if (stmt is AlternativeStmt) { AddComment(builder, stmt, "alternative statement"); @@ -7551,6 +7557,26 @@ namespace Microsoft.Dafny { } } + private void IntroduceAndAssignExistentialVars(ExistsExpr exists, Bpl.StmtListBuilder builder, Bpl.StmtListBuilder builderOutsideIfConstruct, List locals, ExpressionTranslator etran) { + Contract.Requires(exists != null); + Contract.Requires(exists.Range == null); + Contract.Requires(builder != null); + Contract.Requires(builderOutsideIfConstruct != null); + Contract.Requires(locals != null); + Contract.Requires(etran != null); + // declare and havoc the bound variables of 'exists' as local variables + var iesForHavoc = new List(); + foreach (var bv in exists.BoundVars) { + Bpl.Type varType = TrType(bv.Type); + Bpl.Expr wh = GetWhereClause(bv.Tok, new Bpl.IdentifierExpr(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType), bv.Type, etran); + Bpl.Variable local = new Bpl.LocalVariable(bv.Tok, new Bpl.TypedIdent(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh)); + locals.Add(local); + iesForHavoc.Add(new Bpl.IdentifierExpr(local.tok, local)); + } + builderOutsideIfConstruct.Add(new Bpl.HavocCmd(exists.tok, iesForHavoc)); + builder.Add(new Bpl.AssumeCmd(exists.tok, etran.TrExpr(exists.Term))); + } + void TrStmtList(List stmts, Bpl.StmtListBuilder builder, List locals, ExpressionTranslator etran) { Contract.Requires(stmts != null); Contract.Requires(builder != null); @@ -7564,6 +7590,46 @@ namespace Microsoft.Dafny { } } + /// + /// Returns an expression like 'exists' but where the bound variables have been renamed to have + /// 'prefix' as a prefix to their previous names. + /// Assumes the expression has been resolved. + /// + public static Expression AlphaRename(ExistsExpr exists, string prefix, Translator translator) { + Contract.Requires(exists != null); + Contract.Requires(prefix != null); + Contract.Requires(translator != null); + + if (exists.SplitQuantifier != null) { + // TODO: what to do? Substitute(exists.SplitQuantifierExpression); + } + + var substMap = new Dictionary(); + var var4var = new Dictionary(); + var bvars = new List(); + foreach (var bv in exists.BoundVars) { + var newBv = new BoundVar(bv.tok, prefix + bv.Name, bv.Type); + bvars.Add(newBv); + var4var.Add(bv, newBv); + var ie = new IdentifierExpr(newBv.tok, newBv.Name); + ie.Var = newBv; // resolve here + ie.Type = newBv.Type; // resolve here + substMap.Add(bv, ie); + } + var s = new Substituter(null, substMap, new Dictionary(), translator); + var range = exists.Range == null ? null : s.Substitute(exists.Range); + var term = s.Substitute(exists.Term); + var attrs = s.SubstAttributes(exists.Attributes); + var ex = new ExistsExpr(exists.tok, exists.TypeArgs, bvars, range, term, attrs); + if (exists.Bounds != null) { + ex.Bounds = exists.Bounds.ConvertAll(bound => s.SubstituteBoundedPool(bound)); + } + if (exists.MissingBounds != null) { + ex.MissingBounds = exists.MissingBounds.ConvertAll(bv => var4var[bv]); + } + return ex; + } + /// /// Generate: /// havoc Heap \ {this} \ _reads \ _new; @@ -8569,7 +8635,7 @@ namespace Microsoft.Dafny { void TrAlternatives(List alternatives, Bpl.Cmd elseCase0, Bpl.StructuredCmd elseCase1, Bpl.StmtListBuilder builder, List locals, ExpressionTranslator etran) { Contract.Requires(alternatives != null); - Contract.Requires((elseCase0 != null) == (elseCase1 == null)); // ugly way of doing a type union + Contract.Requires((elseCase0 == null) != (elseCase1 == null)); // ugly way of doing a type union Contract.Requires(builder != null); Contract.Requires(locals != null); Contract.Requires(etran != null); @@ -8583,10 +8649,13 @@ namespace Microsoft.Dafny { return; } + // alpha-rename any existential guards + var guards = alternatives.ConvertAll(alt => alt.IsExistentialGuard ? AlphaRename((ExistsExpr)alt.Guard, "eg$", this) : alt.Guard); + // build the negation of the disjunction of all guards (that is, the conjunction of their negations) Bpl.Expr noGuard = Bpl.Expr.True; - foreach (var alternative in alternatives) { - noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(alternative.Guard))); + foreach (var g in guards) { + noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(g))); } var b = new Bpl.StmtListBuilder(); @@ -8605,8 +8674,13 @@ namespace Microsoft.Dafny { CurrentIdGenerator.Push(); var alternative = alternatives[i]; b = new Bpl.StmtListBuilder(); - TrStmt_CheckWellformed(alternative.Guard, b, locals, etran, true); - b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard))); + TrStmt_CheckWellformed(guards[i], b, locals, etran, true); + if (alternative.IsExistentialGuard) { + var exists = (ExistsExpr)alternative.Guard; // the original (that is, not alpha-renamed) guard + IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran); + } else { + b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard))); + } foreach (var s in alternative.Body) { TrStmt(s, b, locals, etran); } @@ -13705,6 +13779,9 @@ namespace Microsoft.Dafny { Contract.Assert(false); // unexpected ComprehensionExpr } } + if (e.Bounds != null) { + ((ComprehensionExpr)newExpr).Bounds = e.Bounds.ConvertAll(bound => SubstituteBoundedPool(bound)); + } // undo any changes to substMap (could be optimized to do this only if newBoundVars != e.BoundVars) foreach (var bv in e.BoundVars) { substMap.Remove(bv); @@ -13761,6 +13838,44 @@ namespace Microsoft.Dafny { } } + public ComprehensionExpr.BoundedPool SubstituteBoundedPool(ComprehensionExpr.BoundedPool bound) { + if (bound == null) { + return null; + } else if (bound is ComprehensionExpr.ExactBoundedPool) { + var b = (ComprehensionExpr.ExactBoundedPool)bound; + return new ComprehensionExpr.ExactBoundedPool(Substitute(b.E)); + } else if (bound is ComprehensionExpr.BoolBoundedPool) { + return bound; // nothing to substitute + } else if (bound is ComprehensionExpr.CharBoundedPool) { + return bound; // nothing to substitute + } else if (bound is ComprehensionExpr.RefBoundedPool) { + return bound; // nothing to substitute + } else if (bound is ComprehensionExpr.IntBoundedPool) { + var b = (ComprehensionExpr.IntBoundedPool)bound; + return new ComprehensionExpr.IntBoundedPool(b.LowerBound == null ? null : Substitute(b.LowerBound), b.UpperBound == null ? null : Substitute(b.UpperBound)); + } else if (bound is ComprehensionExpr.SetBoundedPool) { + var b = (ComprehensionExpr.SetBoundedPool)bound; + return new ComprehensionExpr.SetBoundedPool(Substitute(b.Set)); + } else if (bound is ComprehensionExpr.SubSetBoundedPool) { + var b = (ComprehensionExpr.SubSetBoundedPool)bound; + return new ComprehensionExpr.SubSetBoundedPool(Substitute(b.UpperBound)); + } else if (bound is ComprehensionExpr.SuperSetBoundedPool) { + var b = (ComprehensionExpr.SuperSetBoundedPool)bound; + return new ComprehensionExpr.SuperSetBoundedPool(Substitute(b.LowerBound)); + } else if (bound is ComprehensionExpr.MapBoundedPool) { + var b = (ComprehensionExpr.MapBoundedPool)bound; + return new ComprehensionExpr.MapBoundedPool(Substitute(b.Map)); + } else if (bound is ComprehensionExpr.SeqBoundedPool) { + var b = (ComprehensionExpr.SeqBoundedPool)bound; + return new ComprehensionExpr.SeqBoundedPool(Substitute(b.Seq)); + } else if (bound is ComprehensionExpr.DatatypeBoundedPool) { + return bound; // nothing to substitute + } else { + Contract.Assume(false); // unexpected ComprehensionExpr.BoundedPool + throw new cce.UnreachableException(); // to please compiler + } + } + /// /// Return a list of bound variables, of the same length as 'vars' but with possible substitutions. /// For any change necessary, update 'substMap' to reflect the new substitution; the caller is responsible for diff --git a/Test/dafny0/Compilation.dfy b/Test/dafny0/Compilation.dfy index a2b96996..7f9169da 100644 --- a/Test/dafny0/Compilation.dfy +++ b/Test/dafny0/Compilation.dfy @@ -1,4 +1,4 @@ -// RUN: %dafny "%s" > "%t" +// RUN: %dafny /compile:3 "%s" > "%t" // RUN: %diff "%s.expect" "%t" // The tests in this file are designed to run through the compiler. They contain @@ -43,6 +43,8 @@ module CoRecursion { // 40 // 41 // 42 + // 9 + // 9 method Main() { var m := 17; var cell := new Cell; @@ -58,6 +60,37 @@ module CoRecursion { print l.car, "\n"; l := l.cdr; } + var nio := OneLess(0, 10); + print nio, "\n"; + nio := OneLess'(0, 10); + print nio, "\n"; + } + + method OneLess(lo: int, hi: int) returns (m: int) + requires lo < hi + // This method ensures m == hi - 1, but we don't care to prove it + decreases hi - lo + { + if y :| lo < y < hi { + m := OneLess(y, hi); + } else { + m := lo; + } + } + + method OneLess'(lo: int, hi: int) returns (m: int) + requires lo < hi + // This method ensures m == hi - 1, but we don't care to prove it + decreases hi - lo + { + if { + case y :| lo < y < hi => + m := OneLess'(y, hi); + case lo+1 < hi => + m := OneLess'(lo+1, hi); + case lo + 1 == hi => + m := lo; + } } } diff --git a/Test/dafny0/Compilation.dfy.expect b/Test/dafny0/Compilation.dfy.expect index 0a1938ae..2b76b107 100644 --- a/Test/dafny0/Compilation.dfy.expect +++ b/Test/dafny0/Compilation.dfy.expect @@ -1,3 +1,12 @@ -Dafny program verifier finished with 46 verified, 0 errors -Compiled assembly into Compilation.exe +Dafny program verifier finished with 50 verified, 0 errors +Program compiled successfully +Running... + +400 +320 +40 +41 +42 +9 +9 diff --git a/Test/dafny0/ExistentialGuards.dfy b/Test/dafny0/ExistentialGuards.dfy index 001acb55..5afb3979 100644 --- a/Test/dafny0/ExistentialGuards.dfy +++ b/Test/dafny0/ExistentialGuards.dfy @@ -2,12 +2,19 @@ // RUN: %diff "%s.expect" "%t" predicate P(n: int) +{ + n % 2 == 0 +} predicate R(r: real) +{ + 0.0 <= r +} method M0() { if x :| P(x) { + var y := x + 3; } } @@ -19,13 +26,19 @@ method M1() method M2() { - if x, y :| P(x) && R(y) { + var x := true; + if x, y :| P(x) && R(y) { // this declares a new 'x' + var z := x + 12; } + x := x && false; } method M3() { + var x := true; if x: int, y :| P(x) && R(y) { + var z := x + y.Trunc; + var w := real(x) + y; } } @@ -53,37 +66,94 @@ method M6() } } -method M7() +ghost method M7() returns (z: real, w: real) + ensures -2.0 <= z + ensures z == w // error: does not hold { + var k; if x :| P(x) { + k, z := 4, 18.0; } else if * { + z := z + -z; } else if y :| R(y) { + z := y; } else if y :| P(y) { + k := y; + } else { + z :| R(z); + } + if P(k) { + z := 18.0; + } +} + +ghost method M8(m: int, n: int) + requires forall y :: m <= y < n ==> P(y) +{ + var t := -1; + var u; + if y :| m <= y < n && P(y) { + u := y; + if * { + t := n - y; + } else if * { + t := y - m; + } else if P(y) { + t := 8; + } else { + t := -100; // will never happen + } + } + if t < 0 && m < n { + assert P(m) && !P(m); + assert false; } + assert t < 0 ==> n <= m; } method P0(m: int, n: int) requires m < n { + ghost var even, alsoEven := 4, 8; if { case x :| P(x) => + even := x; case x: int :| P(x) => + even := x; case x, y :| P(x) && R(y) => + even, alsoEven := x, y.Trunc; // this assigns to 'alsoEven' a possibly odd number case x: int, y :| P(x) && R(y) => + even := x; case m < n => // just to be different case x, y: real :| P(x) && R(y) => + even := x; case x: int, y: real :| P(x) && R(y) => + even := x; } + assert P(even); + assert P(alsoEven); // error: may not hold } method P1(m: int, n: int) - requires m < n { + if { // error: missing case + case x :| m <= x < n && P(x) => + } +} + +method P2(m: int, n: int) + requires forall y :: m <= y < n ==> P(y) +{ + if { // error: missing case + case x :| m <= x < n && P(x) => + } +} + +method P3(m: int, n: int) + requires m < n && forall y :: m <= y < n ==> P(y) +{ + assert P(m); // lemma that proves that the following 'if' covers all possibilities if { - case x {:myattribute x, "hello"} :| P(x) => - case x, y {:myattribute y, "sveika"} :| P(x) && R(y) => - case x: int {:myattribute x, "chello"} :| P(x) => - case x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) => - case m < n => + case x :| m <= x < n && P(x) => } } diff --git a/Test/dafny0/ExistentialGuards.dfy.expect b/Test/dafny0/ExistentialGuards.dfy.expect index cf229553..21461067 100644 --- a/Test/dafny0/ExistentialGuards.dfy.expect +++ b/Test/dafny0/ExistentialGuards.dfy.expect @@ -3,12 +3,19 @@ // ExistentialGuards.dfy predicate P(n: int) +{ + n % 2 == 0 +} predicate R(r: real) +{ + 0.0 <= r +} method M0() { if x :| P(x) { + var y := x + 3; } } @@ -20,13 +27,19 @@ method M1() method M2() { + var x := true; if x, y :| P(x) && R(y) { + var z := x + 12; } + x := x && false; } method M3() { + var x := true; if x: int, y :| P(x) && R(y) { + var z := x + y.Trunc; + var w := real(x) + y; } } @@ -54,41 +67,119 @@ method M6() } } -method M7() +ghost method M7() returns (z: real, w: real) + ensures -2.0 <= z + ensures z == w { + var k; if x :| P(x) { + k, z := 4, 18.0; } else if * { + z := z + -z; } else if y :| R(y) { + z := y; } else if y :| P(y) { + k := y; + } else { + z :| R(z); + } + if P(k) { + z := 18.0; } } +ghost method M8(m: int, n: int) + requires forall y :: m <= y < n ==> P(y) +{ + var t := -1; + var u; + if y :| m <= y < n && P(y) { + u := y; + if * { + t := n - y; + } else if * { + t := y - m; + } else if P(y) { + t := 8; + } else { + t := -100; + } + } + if t < 0 && m < n { + assert P(m) && !P(m); + assert false; + } + assert t < 0 ==> n <= m; +} + method P0(m: int, n: int) requires m < n { + ghost var even, alsoEven := 4, 8; if { case x :| P(x) => + even := x; case x: int :| P(x) => + even := x; case x, y :| P(x) && R(y) => + even, alsoEven := x, y.Trunc; case x: int, y :| P(x) && R(y) => + even := x; case m < n => case x, y: real :| P(x) && R(y) => + even := x; case x: int, y: real :| P(x) && R(y) => + even := x; } + assert P(even); + assert P(alsoEven); } method P1(m: int, n: int) - requires m < n { if { - case x {:myattribute x, "hello"} :| P(x) => - case x, y {:myattribute y, "sveika"} :| P(x) && R(y) => - case x: int {:myattribute x, "chello"} :| P(x) => - case x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) => - case m < n => + case x :| m <= x < n && P(x) => + } +} + +method P2(m: int, n: int) + requires forall y :: m <= y < n ==> P(y) +{ + if { + case x :| m <= x < n && P(x) => + } +} + +method P3(m: int, n: int) + requires m < n && forall y :: m <= y < n ==> P(y) +{ + assert P(m); + if { + case x :| m <= x < n && P(x) => } } +ExistentialGuards.dfy(85,10): Error BP5003: A postcondition might not hold on this return path. +ExistentialGuards.dfy(71,12): Related location: This is the postcondition that might not hold. +Execution trace: + (0,0): anon0 + (0,0): anon12_Then + (0,0): anon9 + (0,0): anon16_Then +ExistentialGuards.dfy(134,9): Error: assertion violation +ExistentialGuards.dfy(6,8): Related location +Execution trace: + (0,0): anon0 + (0,0): anon20_Then + (0,0): anon21_Then + (0,0): anon5 + (0,0): anon17 +ExistentialGuards.dfy(139,2): Error: alternative cases fail to cover all possibilties +Execution trace: + (0,0): anon0 + (0,0): anon7_Else +ExistentialGuards.dfy(147,2): Error: alternative cases fail to cover all possibilties +Execution trace: + (0,0): anon0 + (0,0): anon7_Else -Dafny program verifier finished with 22 verified, 0 errors -Compilation error: Function _module._default.P has no body -Compilation error: Function _module._default.R has no body +Dafny program verifier finished with 24 verified, 4 errors diff --git a/Test/dafny0/ExistentialGuardsResolution.dfy b/Test/dafny0/ExistentialGuardsResolution.dfy new file mode 100644 index 00000000..8fce1de5 --- /dev/null +++ b/Test/dafny0/ExistentialGuardsResolution.dfy @@ -0,0 +1,154 @@ +// RUN: %dafny /dprint:- "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +predicate P(n: int) + +predicate R(r: real) + +method M0() +{ + if x :| P(x) { + var y := x + 3; + var x := true; // error: 'x' is already declared in this scope + } +} + +method M1() +{ + if x: int :| P(x) { + x := x + 1; // error: 'x' is an immutable variable + } +} + +method M2() +{ + var x := true; + if x, y :| P(x) && R(y) { // this declares a new 'x' + var z := x + 12; + } + x := x && false; +} + +method M3() +{ + var x := true; + if x: int, y :| P(x) && R(y) { + var z := x + int(y); + var w := real(x) + y; + } + var x := 0.0; // error: 'x' is already declared in this scope +} + +method M4() +{ + if x, y: real :| P(x) && R(y) { + } +} + +method M5() +{ + if x: int, y: real :| P(x) && R(y) { + } +} + +method M6() +{ + if x {:myattribute x, "hello"} :| P(x) { + } + if x, y {:myattribute y, "sveika"} :| P(x) && R(y) { + } + if x: int {:myattribute x, "chello"} :| P(x) { + } + if x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) { + } +} + +method M7() +{ + if x :| P(x) { + } else if * { + } else if y :| R(y) { + } else if y :| P(y) { + } +} + +method P0(m: int, n: int) + requires m < n +{ + var x := true; + if { + case x :| P(x) => + var t := 3 * x; + case x: int :| P(x) => + case x, y :| P(x) && R(y) => + y := y + 1.0; // error: 'y' is an immutable variable + case x: int, y :| P(x) && R(y) => + case m < n => + x := x || m + 5 == n; + case x, y: real :| P(x) && R(y) => + case x: int, y: real :| P(x) && R(y) => + } + assert x; +} + +method P1(m: int, n: int) + requires m < n +{ + if { + case x {:myattribute x, "hello"} :| P(x) => + case x, y {:myattribute y, "sveika"} :| P(x) && R(y) => + case x: int {:myattribute x, "chello"} :| P(x) => + case x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) => + case m < n => + } +} + +module TypesNotFullyDetermined { + method T0() + { + if x :| true { // error: type not entirely resolved + } + } + method T1() + { + if x :| true { + var y := x + 3; + } + } +} + +module Ghost { + predicate P(x: int) // note, P is ghost + predicate method R(x: int) + method M7() returns (z: int, b: bool) + { + if * { + z := z + -z; + } else if y :| 1000 <= y < 2000 && R(y) { + z := y; + } else if y :| 0 <= y < 100 && P(y) { + z := y; // error: not allowed, because the P in the guard makes this a ghost context + } else if y :| 0 <= y < 100 && R(y) { + z := y; // error: this is also in a ghost context, because it depends on the P above + } + + if * { + z := z + -z; + } else if exists y :: 1000 <= y < 2000 && R(y) { + z := 0; + } else if exists y :: 0 <= y < 100 && P(y) { + z := 0; // error: not allowed, because the P in the guard makes this a ghost context + } else if exists y :: 0 <= y < 100 && R(y) { + z := 0; // error: this is also in a ghost context, because it depends on the P above + } + + if P(z) { + z := 20; // error: blatant ghost context + } + + b := exists y :: 0 <= y < 100 && P(y); // error: assignment to non-ghost of something that depends on ghost + ghost var c; + c := exists y :: 0 <= y < 100 && P(y); + b := exists y {:myattribute P(y)} :: 0 <= y < 100; + } +} diff --git a/Test/dafny0/ExistentialGuardsResolution.dfy.expect b/Test/dafny0/ExistentialGuardsResolution.dfy.expect new file mode 100644 index 00000000..681bb13d --- /dev/null +++ b/Test/dafny0/ExistentialGuardsResolution.dfy.expect @@ -0,0 +1,167 @@ +// Dafny program verifier version 1.9.5.20511, Copyright (c) 2003-2015, Microsoft. +// Command Line Options: -nologo -countVerificationErrors:0 -useBaseNameForFileName /dprint:- C:\dafny\Test\dafny0\ExistentialGuardsResolution.dfy +// ExistentialGuardsResolution.dfy + + +module TypesNotFullyDetermined { + method T0() + { + if x :| true { + } + } + + method T1() + { + if x :| true { + var y := x + 3; + } + } +} + +module Ghost { + predicate P(x: int) + + predicate method R(x: int) + + method M7() returns (z: int, b: bool) + { + if * { + z := z + -z; + } else if y :| 1000 <= y < 2000 && R(y) { + z := y; + } else if y :| 0 <= y < 100 && P(y) { + z := y; + } else if y :| 0 <= y < 100 && R(y) { + z := y; + } + if * { + z := z + -z; + } else if exists y :: 1000 <= y < 2000 && R(y) { + z := 0; + } else if exists y :: 0 <= y < 100 && P(y) { + z := 0; + } else if exists y :: 0 <= y < 100 && R(y) { + z := 0; + } + if P(z) { + z := 20; + } + b := exists y :: 0 <= y < 100 && P(y); + ghost var c; + c := exists y :: 0 <= y < 100 && P(y); + b := exists y {:myattribute P(y)} :: 0 <= y < 100; + } +} +predicate P(n: int) + +predicate R(r: real) + +method M0() +{ + if x :| P(x) { + var y := x + 3; + var x := true; + } +} + +method M1() +{ + if x: int :| P(x) { + x := x + 1; + } +} + +method M2() +{ + var x := true; + if x, y :| P(x) && R(y) { + var z := x + 12; + } + x := x && false; +} + +method M3() +{ + var x := true; + if x: int, y :| P(x) && R(y) { + var z := x + int(y); + var w := real(x) + y; + } + var x := 0.0; +} + +method M4() +{ + if x, y: real :| P(x) && R(y) { + } +} + +method M5() +{ + if x: int, y: real :| P(x) && R(y) { + } +} + +method M6() +{ + if x {:myattribute x, "hello"} :| P(x) { + } + if x, y {:myattribute y, "sveika"} :| P(x) && R(y) { + } + if x: int {:myattribute x, "chello"} :| P(x) { + } + if x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) { + } +} + +method M7() +{ + if x :| P(x) { + } else if * { + } else if y :| R(y) { + } else if y :| P(y) { + } +} + +method P0(m: int, n: int) + requires m < n +{ + var x := true; + if { + case x :| P(x) => + var t := 3 * x; + case x: int :| P(x) => + case x, y :| P(x) && R(y) => + y := y + 1.0; + case x: int, y :| P(x) && R(y) => + case m < n => + x := x || m + 5 == n; + case x, y: real :| P(x) && R(y) => + case x: int, y: real :| P(x) && R(y) => + } + assert x; +} + +method P1(m: int, n: int) + requires m < n +{ + if { + case x {:myattribute x, "hello"} :| P(x) => + case x, y {:myattribute y, "sveika"} :| P(x) && R(y) => + case x: int {:myattribute x, "chello"} :| P(x) => + case x {:myattribute x, "hola"} {:yourattribute x + x, "hej"} :| P(x) => + case m < n => + } +} +ExistentialGuardsResolution.dfy(109,7): Error: type of bound variable 'x' could not be determined; please specify the type explicitly +ExistentialGuardsResolution.dfy(130,8): Error: 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) +ExistentialGuardsResolution.dfy(132,8): Error: 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) +ExistentialGuardsResolution.dfy(140,8): Error: 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) +ExistentialGuardsResolution.dfy(142,8): Error: 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) +ExistentialGuardsResolution.dfy(146,8): Error: 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) +ExistentialGuardsResolution.dfy(149,37): Error: function calls are allowed only in specification contexts (consider declaring the function a 'function method') +ExistentialGuardsResolution.dfy(12,8): Error: Duplicate local-variable name: x +ExistentialGuardsResolution.dfy(19,4): Error: LHS of assignment must denote a mutable variable +ExistentialGuardsResolution.dfy(39,6): Error: Duplicate local-variable name: x +ExistentialGuardsResolution.dfy(84,6): Error: LHS of assignment must denote a mutable variable +11 resolution/type errors detected in ExistentialGuardsResolution.dfy diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index e935c83d..58ba6701 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -1692,3 +1692,23 @@ module LoopResolutionTests { } } } + +module UnderspecifiedTypesInAttributes { + function method P(x: T): int + method M() { + var {:myattr var u :| true; 6} v: int; // error: type of u is underspecified + var j {:myattr var u :| true; 6} :| 0 <= j < 100; // error: type of u is underspecified + + var a := new int[100]; + forall lp {:myattr var u :| true; 6} | 0 <= lp < 100 { // error: type of u is underspecified + a[lp] := 0; + } + + modify {:myattr P(10)} {:myattr var u :| true; 6} a; // error: type of u is underspecified + + calc {:myattr P(10)} {:myattr var u :| true; 6} // error: type of u is underspecified + { + 5; + } + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index be19eeac..b055184f 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -161,6 +161,11 @@ ResolutionErrors.dfy(1673,4): Error: 'decreases *' is not allowed on ghost loops ResolutionErrors.dfy(1677,8): Error: 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) ResolutionErrors.dfy(1687,4): Error: 'decreases *' is not allowed on ghost loops ResolutionErrors.dfy(1691,29): Error: 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) +ResolutionErrors.dfy(1699,17): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1700,19): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1703,23): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1707,36): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1709,34): Error: the type of the bound variable 'u' could not be determined ResolutionErrors.dfy(469,2): Error: More than one anonymous constructor ResolutionErrors.dfy(50,13): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(87,14): Error: the name 'Benny' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.Benny') @@ -224,4 +229,4 @@ ResolutionErrors.dfy(1123,8): Error: new cannot be applied to a trait ResolutionErrors.dfy(1144,13): Error: first argument to / must be of numeric type (instead got set) ResolutionErrors.dfy(1151,18): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(1166,14): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -226 resolution/type errors detected in ResolutionErrors.dfy +231 resolution/type errors detected in ResolutionErrors.dfy -- cgit v1.2.3 From 6398bd0f46ed66790d193a4dbcde3e2c0314b833 Mon Sep 17 00:00:00 2001 From: Rustan Leino Date: Mon, 8 Feb 2016 18:58:34 -0800 Subject: Renamed identifiers for increased geopolitical appeal --- Test/dafny0/ResolutionErrors.dfy | 24 +++++++++++----------- Test/dafny0/ResolutionErrors.dfy.expect | 6 +++--- .../some-proofs-only-work-without-autoTriggers.dfy | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'Test/dafny0/ResolutionErrors.dfy.expect') diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 58ba6701..8dceb6ba 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -459,7 +459,7 @@ module MyOwnModule { // ------------------- nameless constructors ------------------------------ -class YHWH { +class Y { var data: int; constructor (x: int) modifies this; @@ -470,22 +470,22 @@ class YHWH { { } method Test() { - var IAmWhoIAm := new YHWH(5); - IAmWhoIAm := new YHWH._ctor(7); // but, in fact, it is also possible to use the underlying name - IAmWhoIAm := new YHWH; // error: the class has a constructor, so one must be used - var s := new Lucifer.Init(5); - s := new Lucifer.FromArray(null); - s := new Lucifer(false); - s := new Lucifer._ctor(false); - s := new Lucifer.M(); // error: there is a constructor, so one must be called - s := new Lucifer; // error: there is a constructor, so one must be called + var i := new Y(5); + i := new Y._ctor(7); // but, in fact, it is also possible to use the underlying name + i := new Y; // error: the class has a constructor, so one must be used + var s := new Luci.Init(5); + s := new Luci.FromArray(null); + s := new Luci(false); + s := new Luci._ctor(false); + s := new Luci.M(); // error: there is a constructor, so one must be called + s := new Luci; // error: there is a constructor, so one must be called var l := new Lamb; l := new Lamb(); // error: there is no default constructor l := new Lamb.Gwen(); } } -class Lucifer { +class Luci { constructor Init(y: int) { } constructor (nameless: bool) { } constructor FromArray(a: array) { } @@ -493,7 +493,7 @@ class Lucifer { } class Lamb { - method Jesus() { } + method Jess() { } method Gwen() { } } diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index b055184f..d1d826f4 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -173,9 +173,9 @@ ResolutionErrors.dfy(92,14): Error: the name 'David' denotes a datatype construc ResolutionErrors.dfy(93,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(95,14): Error: the name 'David' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'Abc.David') ResolutionErrors.dfy(97,18): Error: wrong number of arguments to datatype constructor David (found 2, expected 1) -ResolutionErrors.dfy(475,14): Error: when allocating an object of type 'YHWH', one of its constructor methods must be called -ResolutionErrors.dfy(480,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called -ResolutionErrors.dfy(481,6): Error: when allocating an object of type 'Lucifer', one of its constructor methods must be called +ResolutionErrors.dfy(475,6): Error: when allocating an object of type 'Y', one of its constructor methods must be called +ResolutionErrors.dfy(480,6): Error: when allocating an object of type 'Luci', one of its constructor methods must be called +ResolutionErrors.dfy(481,6): Error: when allocating an object of type 'Luci', one of its constructor methods must be called ResolutionErrors.dfy(483,9): Error: class Lamb does not have an anonymous constructor ResolutionErrors.dfy(853,11): Error: a modifies-clause expression must denote an object or a collection of objects (instead got int) ResolutionErrors.dfy(857,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) diff --git a/Test/triggers/some-proofs-only-work-without-autoTriggers.dfy b/Test/triggers/some-proofs-only-work-without-autoTriggers.dfy index 98cea392..bc2e0934 100644 --- a/Test/triggers/some-proofs-only-work-without-autoTriggers.dfy +++ b/Test/triggers/some-proofs-only-work-without-autoTriggers.dfy @@ -1,7 +1,7 @@ // RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" /autoTriggers:1 /printTooltips "%s" > "%t" // RUN: %diff "%s.expect" "%t" -// The examples below work nicely with /autoTriggers:0, but break when we ass +// The examples below work nicely with /autoTriggers:0, but break when we use // /autoTriggers. // The issue is that the axioms for sequences are missing a number of facts, -- cgit v1.2.3