PageRenderTime 62ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/Dafny/RefinementTransformer.cs

#
C# | 1075 lines | 855 code | 132 blank | 88 comment | 470 complexity | 3c3e08a14480114859e9de017eef1b3c MD5 | raw file
  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  4. //
  5. //-----------------------------------------------------------------------------
  6. // This file contains the transformations that are applied to a module that is
  7. // constructed as a refinement of another. It is invoked during program resolution,
  8. // so the transformation is done syntactically. Upon return from the RefinementTransformer,
  9. // the caller is expected to resolve the resulting module.
  10. //
  11. // As for now (and perhaps this is always the right thing to do), attributes do
  12. // not survive the transformation.
  13. //-----------------------------------------------------------------------------
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Numerics;
  17. using System.Diagnostics.Contracts;
  18. using IToken = Microsoft.Boogie.IToken;
  19. namespace Microsoft.Dafny {
  20. public class RefinementToken : TokenWrapper
  21. {
  22. public readonly ModuleDecl InheritingModule;
  23. public RefinementToken(IToken tok, ModuleDecl m)
  24. : base(tok)
  25. {
  26. Contract.Requires(tok != null);
  27. Contract.Requires(m != null);
  28. this.InheritingModule = m;
  29. }
  30. public static bool IsInherited(IToken tok, ModuleDecl m) {
  31. while (tok is NestedToken) {
  32. var n = (NestedToken)tok;
  33. // check Outer
  34. var r = n.Outer as RefinementToken;
  35. if (r == null || r.InheritingModule != m) {
  36. return false;
  37. }
  38. // continue to check Inner
  39. tok = n.Inner;
  40. }
  41. var rtok = tok as RefinementToken;
  42. return rtok != null && rtok.InheritingModule == m;
  43. }
  44. public override string filename {
  45. get { return WrappedToken.filename + "[" + InheritingModule.Name + "]"; }
  46. set { throw new NotSupportedException(); }
  47. }
  48. }
  49. public class RefinementTransformer
  50. {
  51. ResolutionErrorReporter reporter;
  52. public RefinementTransformer(ResolutionErrorReporter reporter) {
  53. Contract.Requires(reporter != null);
  54. this.reporter = reporter;
  55. }
  56. private ModuleDecl moduleUnderConstruction; // non-null for the duration of Construct calls
  57. public void Construct(ModuleDecl m) {
  58. Contract.Requires(m != null);
  59. Contract.Requires(m.RefinementBase != null);
  60. Contract.Assert(moduleUnderConstruction == null);
  61. moduleUnderConstruction = m;
  62. var prev = m.RefinementBase;
  63. // Include the imports of the base. Note, prev is itself NOT added as an import
  64. // of m; instead, the contents from prev is merged directly into m.
  65. // (Here, we change the import declarations. But edges for these imports will
  66. // not be added to the importGraph of the calling resolver. However, the refines
  67. // clause gave rise to an edge in the importGraph, so the transitive import edges
  68. // are represented in the importGraph.)
  69. foreach (var im in prev.Imports) {
  70. if (!m.ImportNames.Contains(im.Name)) {
  71. m.ImportNames.Add(im.Name);
  72. m.Imports.Add(im);
  73. }
  74. }
  75. // Create a simple name-to-decl dictionary. Ignore any duplicates at this time.
  76. var declaredNames = new Dictionary<string, int>();
  77. for (int i = 0; i < m.TopLevelDecls.Count; i++) {
  78. var d = m.TopLevelDecls[i];
  79. if (!declaredNames.ContainsKey(d.Name)) {
  80. declaredNames.Add(d.Name, i);
  81. }
  82. }
  83. // Merge the declarations of prev into the declarations of m
  84. foreach (var d in prev.TopLevelDecls) {
  85. int index;
  86. if (!declaredNames.TryGetValue(d.Name, out index)) {
  87. m.TopLevelDecls.Add(CloneDeclaration(d, m));
  88. } else {
  89. var nw = m.TopLevelDecls[index];
  90. if (d is ArbitraryTypeDecl) {
  91. // this is allowed to be refined by any type declaration, so just keep the new one
  92. } else if (nw is ArbitraryTypeDecl) {
  93. reporter.Error(nw, "an arbitrary type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base", nw.Name);
  94. } else if (nw is DatatypeDecl) {
  95. reporter.Error(nw, "a datatype declaration ({0}) in a refinement module can only replace an arbitrary-type declaration", nw.Name);
  96. } else {
  97. Contract.Assert(nw is ClassDecl);
  98. if (d is DatatypeDecl) {
  99. reporter.Error(nw, "a class declaration ({0}) in a refining module cannot replace a datatype declaration in the refinement base", nw.Name);
  100. } else {
  101. m.TopLevelDecls[index] = MergeClass((ClassDecl)nw, (ClassDecl)d);
  102. }
  103. }
  104. }
  105. }
  106. Contract.Assert(moduleUnderConstruction == m);
  107. moduleUnderConstruction = null;
  108. }
  109. IToken Tok(IToken tok) {
  110. if (moduleUnderConstruction == null) {
  111. return tok;
  112. } else {
  113. return new RefinementToken(tok, moduleUnderConstruction);
  114. }
  115. }
  116. // -------------------------------------------------- Cloning ---------------------------------------------------------------
  117. TopLevelDecl CloneDeclaration(TopLevelDecl d, ModuleDecl m) {
  118. Contract.Requires(d != null);
  119. Contract.Requires(m != null);
  120. if (d is ArbitraryTypeDecl) {
  121. var dd = (ArbitraryTypeDecl)d;
  122. return new ArbitraryTypeDecl(Tok(dd.tok), dd.Name, m, null);
  123. } else if (d is DatatypeDecl) {
  124. var dd = (DatatypeDecl)d;
  125. var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
  126. var ctors = dd.Ctors.ConvertAll(CloneCtor);
  127. var dt = new DatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, null);
  128. return dt;
  129. } else if (d is ClassDecl) {
  130. var dd = (ClassDecl)d;
  131. var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
  132. var mm = dd.Members.ConvertAll(CloneMember);
  133. var cl = new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, null);
  134. return cl;
  135. } else {
  136. Contract.Assert(false); // unexpected declaration
  137. return null; // to please compiler
  138. }
  139. }
  140. DatatypeCtor CloneCtor(DatatypeCtor ct) {
  141. return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), null);
  142. }
  143. TypeParameter CloneTypeParam(TypeParameter tp) {
  144. return new TypeParameter(Tok(tp.tok), tp.Name);
  145. }
  146. MemberDecl CloneMember(MemberDecl member) {
  147. if (member is Field) {
  148. var f = (Field)member;
  149. return new Field(Tok(f.tok), f.Name, f.IsGhost, f.IsMutable, CloneType(f.Type), null);
  150. } else if (member is Function) {
  151. var f = (Function)member;
  152. return CloneFunction(Tok(f.tok), f, f.IsGhost, null, null, null);
  153. } else {
  154. var m = (Method)member;
  155. return CloneMethod(m, null, null);
  156. }
  157. }
  158. Type CloneType(Type t) {
  159. if (t is BasicType) {
  160. return t;
  161. } else if (t is SetType) {
  162. var tt = (SetType)t;
  163. return new SetType(tt.Arg);
  164. } else if (t is SeqType) {
  165. var tt = (SeqType)t;
  166. return new SeqType(tt.Arg);
  167. } else if (t is MultiSetType) {
  168. var tt = (MultiSetType)t;
  169. return new MultiSetType(tt.Arg);
  170. } else if (t is UserDefinedType) {
  171. var tt = (UserDefinedType)t;
  172. return new UserDefinedType(Tok(tt.tok), tt.Name, tt.TypeArgs.ConvertAll(CloneType));
  173. } else if (t is InferredTypeProxy) {
  174. return new InferredTypeProxy();
  175. } else {
  176. Contract.Assert(false); // unexpected type (e.g., no other type proxies are expected at this time)
  177. return null; // to please compiler
  178. }
  179. }
  180. Formal CloneFormal(Formal formal) {
  181. return new Formal(Tok(formal.tok), formal.Name, CloneType(formal.Type), formal.InParam, formal.IsGhost);
  182. }
  183. BoundVar CloneBoundVar(BoundVar bv) {
  184. return new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.Type));
  185. }
  186. Specification<Expression> CloneSpecExpr(Specification<Expression> spec) {
  187. var ee = spec.Expressions == null ? null : spec.Expressions.ConvertAll(CloneExpr);
  188. return new Specification<Expression>(ee, null);
  189. }
  190. Specification<FrameExpression> CloneSpecFrameExpr(Specification<FrameExpression> frame) {
  191. var ee = frame.Expressions == null ? null : frame.Expressions.ConvertAll(CloneFrameExpr);
  192. return new Specification<FrameExpression>(ee, null);
  193. }
  194. FrameExpression CloneFrameExpr(FrameExpression frame) {
  195. return new FrameExpression(CloneExpr(frame.E), frame.FieldName);
  196. }
  197. Attributes.Argument CloneAttrArg(Attributes.Argument aa) {
  198. if (aa.E != null) {
  199. return new Attributes.Argument(Tok(aa.Tok), CloneExpr(aa.E));
  200. } else {
  201. return new Attributes.Argument(Tok(aa.Tok), aa.S);
  202. }
  203. }
  204. MaybeFreeExpression CloneMayBeFreeExpr(MaybeFreeExpression expr) {
  205. return new MaybeFreeExpression(CloneExpr(expr.E), expr.IsFree);
  206. }
  207. Expression CloneExpr(Expression expr) {
  208. if (expr == null) {
  209. return null;
  210. } else if (expr is LiteralExpr) {
  211. var e = (LiteralExpr)expr;
  212. if (e.Value == null) {
  213. return new LiteralExpr(Tok(e.tok));
  214. } else if (e.Value is bool) {
  215. return new LiteralExpr(Tok(e.tok), (bool)e.Value);
  216. } else {
  217. return new LiteralExpr(Tok(e.tok), (BigInteger)e.Value);
  218. }
  219. } else if (expr is ThisExpr) {
  220. if (expr is ImplicitThisExpr) {
  221. return new ImplicitThisExpr(Tok(expr.tok));
  222. } else {
  223. return new ThisExpr(Tok(expr.tok));
  224. }
  225. } else if (expr is IdentifierExpr) {
  226. var e = (IdentifierExpr)expr;
  227. return new IdentifierExpr(Tok(e.tok), e.Name);
  228. } else if (expr is DatatypeValue) {
  229. var e = (DatatypeValue)expr;
  230. return new DatatypeValue(Tok(e.tok), e.DatatypeName, e.MemberName, e.Arguments.ConvertAll(CloneExpr));
  231. } else if (expr is DisplayExpression) {
  232. DisplayExpression e = (DisplayExpression)expr;
  233. if (expr is SetDisplayExpr) {
  234. return new SetDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));
  235. } else if (expr is MultiSetDisplayExpr) {
  236. return new MultiSetDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));
  237. } else {
  238. Contract.Assert(expr is SeqDisplayExpr);
  239. return new SeqDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));
  240. }
  241. } else if (expr is ExprDotName) {
  242. var e = (ExprDotName)expr;
  243. return new ExprDotName(Tok(e.tok), CloneExpr(e.Obj), e.SuffixName);
  244. } else if (expr is FieldSelectExpr) {
  245. var e = (FieldSelectExpr)expr;
  246. return new FieldSelectExpr(Tok(e.tok), CloneExpr(e.Obj), e.FieldName);
  247. } else if (expr is SeqSelectExpr) {
  248. var e = (SeqSelectExpr)expr;
  249. return new SeqSelectExpr(Tok(e.tok), e.SelectOne, CloneExpr(e.Seq), CloneExpr(e.E0), CloneExpr(e.E1));
  250. } else if (expr is MultiSelectExpr) {
  251. var e = (MultiSelectExpr)expr;
  252. return new MultiSelectExpr(Tok(e.tok), CloneExpr(e.Array), e.Indices.ConvertAll(CloneExpr));
  253. } else if (expr is SeqUpdateExpr) {
  254. var e = (SeqUpdateExpr)expr;
  255. return new SeqUpdateExpr(Tok(e.tok), CloneExpr(e.Seq), CloneExpr(e.Index), CloneExpr(e.Value));
  256. } else if (expr is FunctionCallExpr) {
  257. var e = (FunctionCallExpr)expr;
  258. return new FunctionCallExpr(Tok(e.tok), e.Name, CloneExpr(e.Receiver), e.OpenParen == null ? null : Tok(e.OpenParen), e.Args.ConvertAll(CloneExpr));
  259. } else if (expr is OldExpr) {
  260. var e = (OldExpr)expr;
  261. return new OldExpr(Tok(e.tok), CloneExpr(e.E));
  262. } else if (expr is MultiSetFormingExpr) {
  263. var e = (MultiSetFormingExpr)expr;
  264. return new MultiSetFormingExpr(Tok(e.tok), CloneExpr(e.E));
  265. } else if (expr is FreshExpr) {
  266. var e = (FreshExpr)expr;
  267. return new FreshExpr(Tok(e.tok), CloneExpr(e.E));
  268. } else if (expr is AllocatedExpr) {
  269. var e = (AllocatedExpr)expr;
  270. return new AllocatedExpr(Tok(e.tok), CloneExpr(e.E));
  271. } else if (expr is UnaryExpr) {
  272. var e = (UnaryExpr)expr;
  273. return new UnaryExpr(Tok(e.tok), e.Op, CloneExpr(e.E));
  274. } else if (expr is BinaryExpr) {
  275. var e = (BinaryExpr)expr;
  276. return new BinaryExpr(Tok(e.tok), e.Op, CloneExpr(e.E0), CloneExpr(e.E1));
  277. } else if (expr is ChainingExpression) {
  278. var e = (ChainingExpression)expr;
  279. return CloneExpr(e.E); // just clone the desugaring, since it's already available
  280. } else if (expr is LetExpr) {
  281. var e = (LetExpr)expr;
  282. return new LetExpr(Tok(e.tok), e.Vars.ConvertAll(CloneBoundVar), e.RHSs.ConvertAll(CloneExpr), CloneExpr(e.Body));
  283. } else if (expr is ComprehensionExpr) {
  284. var e = (ComprehensionExpr)expr;
  285. var tk = Tok(e.tok);
  286. var bvs = e.BoundVars.ConvertAll(CloneBoundVar);
  287. var range = CloneExpr(e.Range);
  288. var term = CloneExpr(e.Term);
  289. if (e is ForallExpr) {
  290. return new ForallExpr(tk, bvs, range, term, null);
  291. } else if (e is ExistsExpr) {
  292. return new ExistsExpr(tk, bvs, range, term, null);
  293. } else {
  294. Contract.Assert(e is SetComprehension);
  295. return new SetComprehension(tk, bvs, range, term);
  296. }
  297. } else if (expr is WildcardExpr) {
  298. return new WildcardExpr(Tok(expr.tok));
  299. } else if (expr is PredicateExpr) {
  300. var e = (PredicateExpr)expr;
  301. if (e is AssertExpr) {
  302. return new AssertExpr(Tok(e.tok), CloneExpr(e.Guard), CloneExpr(e.Body));
  303. } else {
  304. Contract.Assert(e is AssumeExpr);
  305. return new AssumeExpr(Tok(e.tok), CloneExpr(e.Guard), CloneExpr(e.Body));
  306. }
  307. } else if (expr is ITEExpr) {
  308. var e = (ITEExpr)expr;
  309. return new ITEExpr(Tok(e.tok), CloneExpr(e.Test), CloneExpr(e.Thn), CloneExpr(e.Els));
  310. } else if (expr is ParensExpression) {
  311. var e = (ParensExpression)expr;
  312. return CloneExpr(e.E); // skip the parentheses in the clone
  313. } else if (expr is IdentifierSequence) {
  314. var e = (IdentifierSequence)expr;
  315. var aa = e.Arguments == null ? null : e.Arguments.ConvertAll(CloneExpr);
  316. return new IdentifierSequence(e.Tokens.ConvertAll(tk => Tok(tk)), e.OpenParen == null ? null : Tok(e.OpenParen), aa);
  317. } else if (expr is MatchExpr) {
  318. var e = (MatchExpr)expr;
  319. return new MatchExpr(Tok(e.tok), CloneExpr(e.Source),
  320. e.Cases.ConvertAll(c => new MatchCaseExpr(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body))));
  321. } else {
  322. Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
  323. }
  324. }
  325. AssignmentRhs CloneRHS(AssignmentRhs rhs) {
  326. if (rhs is ExprRhs) {
  327. var r = (ExprRhs)rhs;
  328. return new ExprRhs(CloneExpr(r.Expr));
  329. } else if (rhs is HavocRhs) {
  330. return new HavocRhs(Tok(rhs.Tok));
  331. } else {
  332. var r = (TypeRhs)rhs;
  333. if (r.ArrayDimensions != null) {
  334. return new TypeRhs(Tok(r.Tok), CloneType(r.EType), r.ArrayDimensions.ConvertAll(CloneExpr));
  335. } else if (r.InitCall != null) {
  336. return new TypeRhs(Tok(r.Tok), CloneType(r.EType), (CallStmt)CloneStmt(r.InitCall));
  337. } else {
  338. return new TypeRhs(Tok(r.Tok), CloneType(r.EType));
  339. }
  340. }
  341. }
  342. BlockStmt CloneBlockStmt(BlockStmt stmt) {
  343. if (stmt == null) {
  344. return null;
  345. } else {
  346. return new BlockStmt(Tok(stmt.Tok), stmt.Body.ConvertAll(CloneStmt));
  347. }
  348. }
  349. Statement CloneStmt(Statement stmt) {
  350. if (stmt == null) {
  351. return null;
  352. }
  353. Statement r;
  354. if (stmt is AssertStmt) {
  355. var s = (AssertStmt)stmt;
  356. r = new AssertStmt(Tok(s.Tok), CloneExpr(s.Expr));
  357. } else if (stmt is AssumeStmt) {
  358. var s = (AssumeStmt)stmt;
  359. r = new AssumeStmt(Tok(s.Tok), CloneExpr(s.Expr));
  360. } else if (stmt is PrintStmt) {
  361. var s = (PrintStmt)stmt;
  362. r = new PrintStmt(Tok(s.Tok), s.Args.ConvertAll(CloneAttrArg));
  363. } else if (stmt is BreakStmt) {
  364. var s = (BreakStmt)stmt;
  365. if (s.TargetLabel != null) {
  366. r = new BreakStmt(Tok(s.Tok), s.TargetLabel);
  367. } else {
  368. r = new BreakStmt(Tok(s.Tok), s.BreakCount);
  369. }
  370. } else if (stmt is ReturnStmt) {
  371. var s = (ReturnStmt)stmt;
  372. r = new ReturnStmt(Tok(s.Tok), s.rhss == null ? null : s.rhss.ConvertAll(CloneRHS));
  373. } else if (stmt is AssignStmt) {
  374. var s = (AssignStmt)stmt;
  375. r = new AssignStmt(Tok(s.Tok), CloneExpr(s.Lhs), CloneRHS(s.Rhs));
  376. } else if (stmt is VarDecl) {
  377. var s = (VarDecl)stmt;
  378. r = new VarDecl(Tok(s.Tok), s.Name, CloneType(s.OptionalType), s.IsGhost);
  379. } else if (stmt is CallStmt) {
  380. var s = (CallStmt)stmt;
  381. r = new CallStmt(Tok(s.Tok), s.Lhs.ConvertAll(CloneExpr), CloneExpr(s.Receiver), s.MethodName, s.Args.ConvertAll(CloneExpr));
  382. } else if (stmt is BlockStmt) {
  383. r = CloneBlockStmt((BlockStmt)stmt);
  384. } else if (stmt is IfStmt) {
  385. var s = (IfStmt)stmt;
  386. r = new IfStmt(Tok(s.Tok), CloneExpr(s.Guard), CloneBlockStmt(s.Thn), CloneStmt(s.Els));
  387. } else if (stmt is AlternativeStmt) {
  388. var s = (AlternativeStmt)stmt;
  389. r = new AlternativeStmt(Tok(s.Tok), s.Alternatives.ConvertAll(CloneGuardedAlternative));
  390. } else if (stmt is WhileStmt) {
  391. var s = (WhileStmt)stmt;
  392. r = new WhileStmt(Tok(s.Tok), CloneExpr(s.Guard), s.Invariants.ConvertAll(CloneMayBeFreeExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), CloneBlockStmt(s.Body));
  393. } else if (stmt is AlternativeLoopStmt) {
  394. var s = (AlternativeLoopStmt)stmt;
  395. r = new AlternativeLoopStmt(Tok(s.Tok), s.Invariants.ConvertAll(CloneMayBeFreeExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), s.Alternatives.ConvertAll(CloneGuardedAlternative));
  396. } else if (stmt is ParallelStmt) {
  397. var s = (ParallelStmt)stmt;
  398. r = new ParallelStmt(Tok(s.Tok), s.BoundVars.ConvertAll(CloneBoundVar), null, CloneExpr(s.Range), s.Ens.ConvertAll(CloneMayBeFreeExpr), CloneStmt(s.Body));
  399. } else if (stmt is MatchStmt) {
  400. var s = (MatchStmt)stmt;
  401. r = new MatchStmt(Tok(s.Tok), CloneExpr(s.Source),
  402. s.Cases.ConvertAll(c => new MatchCaseStmt(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), c.Body.ConvertAll(CloneStmt))));
  403. } else if (stmt is UpdateStmt) {
  404. var s = (UpdateStmt)stmt;
  405. r = new UpdateStmt(Tok(s.Tok), s.Lhss.ConvertAll(CloneExpr), s.Rhss.ConvertAll(CloneRHS), s.CanMutateKnownState);
  406. } else if (stmt is VarDeclStmt) {
  407. var s = (VarDeclStmt)stmt;
  408. r = new VarDeclStmt(Tok(s.Tok), s.Lhss.ConvertAll(c => (VarDecl)CloneStmt(c)), (UpdateStmt)CloneStmt(s.Update));
  409. } else {
  410. Contract.Assert(false); throw new cce.UnreachableException(); // unexpected statement
  411. }
  412. // add labels to the cloned statement
  413. AddStmtLabels(r, stmt.Labels);
  414. return r;
  415. }
  416. void AddStmtLabels(Statement s, LabelNode node) {
  417. if (node != null) {
  418. AddStmtLabels(s, node.Next);
  419. if (node.Label == null) {
  420. // this indicates an implicit-target break statement that has been resolved; don't add it
  421. } else {
  422. s.Labels = new LabelNode(Tok(node.Tok), node.Label, s.Labels);
  423. }
  424. }
  425. }
  426. GuardedAlternative CloneGuardedAlternative(GuardedAlternative alt) {
  427. return new GuardedAlternative(Tok(alt.Tok), CloneExpr(alt.Guard), alt.Body.ConvertAll(CloneStmt));
  428. }
  429. Function CloneFunction(IToken tok, Function f, bool isGhost, List<Expression> moreEnsures, Expression moreBody, Expression replacementBody) {
  430. Contract.Requires(moreBody == null || f is Predicate);
  431. Contract.Requires(moreBody == null || replacementBody == null);
  432. var tps = f.TypeArgs.ConvertAll(CloneTypeParam);
  433. var formals = f.Formals.ConvertAll(CloneFormal);
  434. var req = f.Req.ConvertAll(CloneExpr);
  435. var reads = f.Reads.ConvertAll(CloneFrameExpr);
  436. var decreases = CloneSpecExpr(f.Decreases);
  437. var previousModuleUnderConstruction = moduleUnderConstruction;
  438. if (moreBody != null || replacementBody != null) { moduleUnderConstruction = null; }
  439. var ens = f.Ens.ConvertAll(CloneExpr);
  440. moduleUnderConstruction = previousModuleUnderConstruction;
  441. if (moreEnsures != null) {
  442. ens.AddRange(moreEnsures);
  443. }
  444. Expression body;
  445. if (replacementBody != null) {
  446. body = replacementBody;
  447. } else if (moreBody != null) {
  448. if (f.Body == null) {
  449. body = moreBody;
  450. } else {
  451. body = new BinaryExpr(f.tok, BinaryExpr.Opcode.And, CloneExpr(f.Body), moreBody);
  452. }
  453. } else {
  454. body = CloneExpr(f.Body);
  455. }
  456. if (f is Predicate) {
  457. return new Predicate(tok, f.Name, f.IsStatic, isGhost, f.IsUnlimited, tps, f.OpenParen, formals,
  458. req, reads, ens, decreases, body, moreBody != null, null, false);
  459. } else {
  460. return new Function(tok, f.Name, f.IsStatic, isGhost, f.IsUnlimited, tps, f.OpenParen, formals, CloneType(f.ResultType),
  461. req, reads, ens, decreases, body, null, false);
  462. }
  463. }
  464. Method CloneMethod(Method m, List<MaybeFreeExpression> moreEnsures, BlockStmt replacementBody) {
  465. Contract.Requires(m != null);
  466. var tps = m.TypeArgs.ConvertAll(CloneTypeParam);
  467. var ins = m.Ins.ConvertAll(CloneFormal);
  468. var req = m.Req.ConvertAll(CloneMayBeFreeExpr);
  469. var mod = CloneSpecFrameExpr(m.Mod);
  470. var decreases = CloneSpecExpr(m.Decreases);
  471. var previousModuleUnderConstruction = moduleUnderConstruction;
  472. if (replacementBody != null) { moduleUnderConstruction = null; }
  473. var ens = m.Ens.ConvertAll(CloneMayBeFreeExpr);
  474. if (replacementBody != null) { moduleUnderConstruction = previousModuleUnderConstruction; }
  475. if (moreEnsures != null) {
  476. ens.AddRange(moreEnsures);
  477. }
  478. var body = replacementBody ?? CloneBlockStmt(m.Body);
  479. if (m is Constructor) {
  480. return new Constructor(Tok(m.tok), m.Name, tps, ins,
  481. req, mod, ens, decreases, body, null, false);
  482. } else {
  483. return new Method(Tok(m.tok), m.Name, m.IsStatic, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal),
  484. req, mod, ens, decreases, body, null, false);
  485. }
  486. }
  487. // -------------------------------------------------- Merging ---------------------------------------------------------------
  488. ClassDecl MergeClass(ClassDecl nw, ClassDecl prev) {
  489. // Create a simple name-to-member dictionary. Ignore any duplicates at this time.
  490. var declaredNames = new Dictionary<string, int>();
  491. for (int i = 0; i < nw.Members.Count; i++) {
  492. var member = nw.Members[i];
  493. if (!declaredNames.ContainsKey(member.Name)) {
  494. declaredNames.Add(member.Name, i);
  495. }
  496. }
  497. // Merge the declarations of prev into the declarations of m
  498. foreach (var member in prev.Members) {
  499. int index;
  500. if (!declaredNames.TryGetValue(member.Name, out index)) {
  501. nw.Members.Add(CloneMember(member));
  502. } else {
  503. var nwMember = nw.Members[index];
  504. if (nwMember is Field) {
  505. reporter.Error(nwMember, "a field declaration ({0}) in a refining class ({1}) is not allowed replace an existing declaration in the refinement base", nwMember.Name, nw.Name);
  506. } else if (nwMember is Function) {
  507. var f = (Function)nwMember;
  508. bool isPredicate = f is Predicate;
  509. string s = isPredicate ? "predicate" : "function";
  510. if (!(member is Function) || isPredicate && !(member is Predicate)) {
  511. reporter.Error(nwMember, "a {0} declaration ({1}) can only refine a {0}", s, nwMember.Name);
  512. } else {
  513. var prevFunction = (Function)member;
  514. if (f.Req.Count != 0) {
  515. reporter.Error(f.Req[0].tok, "a refining {0} is not allowed to add preconditions", s);
  516. }
  517. if (f.Reads.Count != 0) {
  518. reporter.Error(f.Reads[0].E.tok, "a refining {0} is not allowed to extend the reads clause", s);
  519. }
  520. if (f.Decreases.Expressions.Count != 0) {
  521. reporter.Error(f.Decreases.Expressions[0].tok, "decreases clause on refining {0} not supported", s);
  522. }
  523. if (prevFunction.IsStatic != f.IsStatic) {
  524. reporter.Error(f, "a function in a refining module cannot be changed from static to non-static or vice versa: {0}", f.Name);
  525. }
  526. if (prevFunction.IsUnlimited != f.IsUnlimited) {
  527. reporter.Error(f, "a function in a refining module cannot be changed from unlimited to limited or vice versa: {0}", f.Name);
  528. }
  529. if (!prevFunction.IsGhost && f.IsGhost) {
  530. reporter.Error(f, "a function method cannot be changed into a (ghost) function in a refining module: {0}", f.Name);
  531. } else if (prevFunction.IsGhost && !f.IsGhost && prevFunction.Body != null) {
  532. reporter.Error(f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name);
  533. }
  534. if (f.SignatureIsOmitted) {
  535. Contract.Assert(f.TypeArgs.Count == 0);
  536. Contract.Assert(f.Formals.Count == 0);
  537. } else {
  538. CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function");
  539. CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter");
  540. if (!TypesAreEqual(prevFunction.ResultType, f.ResultType)) {
  541. reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
  542. }
  543. }
  544. Expression moreBody = null;
  545. Expression replacementBody = null;
  546. if (isPredicate) {
  547. moreBody = f.Body;
  548. } else if (prevFunction.Body == null) {
  549. replacementBody = f.Body;
  550. } else if (f.Body != null) {
  551. reporter.Error(nwMember, "a refining function is not allowed to extend/change the body");
  552. }
  553. nw.Members[index] = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, moreBody, replacementBody);
  554. }
  555. } else {
  556. var m = (Method)nwMember;
  557. if (!(member is Method)) {
  558. reporter.Error(nwMember, "a method declaration ({0}) can only refine a method", nwMember.Name);
  559. } else {
  560. var prevMethod = (Method)member;
  561. if (m.Req.Count != 0) {
  562. reporter.Error(m.Req[0].E.tok, "a refining method is not allowed to add preconditions");
  563. }
  564. if (m.Mod.Expressions.Count != 0) {
  565. reporter.Error(m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause");
  566. }
  567. if (m.Decreases.Expressions.Count != 0) {
  568. reporter.Error(m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported");
  569. }
  570. if (prevMethod.IsStatic != m.IsStatic) {
  571. reporter.Error(m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name);
  572. }
  573. if (prevMethod.IsGhost && !m.IsGhost) {
  574. reporter.Error(m, "a method cannot be changed into a ghost method in a refining module: {0}", m.Name);
  575. } else if (!prevMethod.IsGhost && m.IsGhost) {
  576. reporter.Error(m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name);
  577. }
  578. if (m.SignatureIsOmitted) {
  579. Contract.Assert(m.TypeArgs.Count == 0);
  580. Contract.Assert(m.Ins.Count == 0);
  581. Contract.Assert(m.Outs.Count == 0);
  582. } else {
  583. CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, "method");
  584. CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter");
  585. CheckAgreement_Parameters(m.tok, prevMethod.Outs, m.Outs, m.Name, "method", "out-parameter");
  586. }
  587. var replacementBody = m.Body;
  588. if (replacementBody != null) {
  589. if (prevMethod.Body == null) {
  590. // cool
  591. } else {
  592. replacementBody = MergeBlockStmt(replacementBody, prevMethod.Body);
  593. }
  594. }
  595. nw.Members[index] = CloneMethod(prevMethod, m.Ens, replacementBody);
  596. }
  597. }
  598. }
  599. }
  600. return nw;
  601. }
  602. void CheckAgreement_TypeParameters(IToken tok, List<TypeParameter> old, List<TypeParameter> nw, string name, string thing) {
  603. Contract.Requires(tok != null);
  604. Contract.Requires(old != null);
  605. Contract.Requires(nw != null);
  606. Contract.Requires(name != null);
  607. Contract.Requires(thing != null);
  608. if (old.Count != nw.Count) {
  609. reporter.Error(tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines", thing, name, nw.Count, old.Count);
  610. } else {
  611. for (int i = 0; i < old.Count; i++) {
  612. var o = old[i];
  613. var n = nw[i];
  614. if (o.Name != n.Name) {
  615. reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name);
  616. }
  617. }
  618. }
  619. }
  620. void CheckAgreement_Parameters(IToken tok, List<Formal> old, List<Formal> nw, string name, string thing, string parameterKind) {
  621. Contract.Requires(tok != null);
  622. Contract.Requires(old != null);
  623. Contract.Requires(nw != null);
  624. Contract.Requires(name != null);
  625. Contract.Requires(thing != null);
  626. Contract.Requires(parameterKind != null);
  627. if (old.Count != nw.Count) {
  628. reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
  629. } else {
  630. for (int i = 0; i < old.Count; i++) {
  631. var o = old[i];
  632. var n = nw[i];
  633. if (o.Name != n.Name) {
  634. reporter.Error(n.tok, "there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines", parameterKind, i, n.Name, o.Name, thing, name);
  635. } else if (!o.IsGhost && n.IsGhost) {
  636. reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
  637. } else if (o.IsGhost && !n.IsGhost) {
  638. reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
  639. } else if (!TypesAreEqual(o.Type, n.Type)) {
  640. reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
  641. }
  642. }
  643. }
  644. }
  645. bool TypesAreEqual(Type t, Type u) {
  646. Contract.Requires(t != null);
  647. Contract.Requires(u != null);
  648. return t.ToString() == u.ToString();
  649. }
  650. BlockStmt MergeBlockStmt(BlockStmt skeleton, BlockStmt oldStmt) {
  651. Contract.Requires(skeleton != null);
  652. Contract.Requires(oldStmt != null);
  653. var body = new List<Statement>();
  654. int i = 0, j = 0;
  655. while (i < skeleton.Body.Count) {
  656. var cur = skeleton.Body[i];
  657. if (j == oldStmt.Body.Count) {
  658. if (!(cur is SkeletonStatement)) {
  659. MergeAddStatement(cur, body);
  660. } else if (((SkeletonStatement)cur).S == null) {
  661. // the "..." matches the empty statement sequence
  662. } else {
  663. reporter.Error(cur.Tok, "skeleton statement does not match old statement");
  664. }
  665. i++;
  666. } else {
  667. var oldS = oldStmt.Body[j];
  668. /* See how the two statements match up.
  669. * cur oldS result
  670. * ------ ------ ------
  671. * assert ...; assume E; assert E;
  672. * assert ...; assert E; assert E;
  673. * assert E; assert E;
  674. *
  675. * var x:=E; var x; var x:=E;
  676. * var VarProduction; var VarProduction;
  677. *
  678. * if ... Then else Else if (G) Then' else Else' if (G) Merge(Then,Then') else Merge(Else,Else')
  679. * if (G) Then else Else if (*) Then' else Else' if (G) Merge(Then,Then') else Merge(Else,Else')
  680. *
  681. * while ... LoopSpec ... while (G) LoopSpec' Body while (G) Merge(LoopSpec,LoopSpec') Body
  682. * while ... LoopSpec Body while (G) LoopSpec' Body' while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')
  683. * while (G) LoopSpec ... while (*) LoopSpec' Body while (G) Merge(LoopSpec,LoopSpec') Body
  684. * while (G) LoopSpec Body while (*) LoopSpec' Body' while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')
  685. *
  686. * ...; S StmtThatDoesNotMatchS; S' StatementThatDoesNotMatchS; Merge( ...;S , S')
  687. *
  688. * Note, LoopSpec must contain only invariant declarations (as the parser ensures for the first three cases).
  689. * Note, there is an implicit "...;" at the end of every block in a skeleton.
  690. *
  691. * TODO: should also handle labels and some form of new "replace" statement
  692. */
  693. if (cur is SkeletonStatement) {
  694. var S = ((SkeletonStatement)cur).S;
  695. if (S == null) {
  696. if (i + 1 == skeleton.Body.Count) {
  697. // this "...;" is the last statement of the skeleton, so treat it like the default case
  698. } else {
  699. var nxt = skeleton.Body[i+1];
  700. if (nxt is SkeletonStatement && ((SkeletonStatement)nxt).S == null) {
  701. // "...; ...;" is the same as just "...;", so skip this one
  702. } else {
  703. // skip up until the next thing that matches "nxt"
  704. while (!PotentialMatch(nxt, oldS)) {
  705. // loop invariant: oldS == oldStmt.Body[j]
  706. body.Add(CloneStmt(oldS));
  707. j++;
  708. if (j == oldStmt.Body.Count) { break; }
  709. oldS = oldStmt.Body[j];
  710. }
  711. }
  712. }
  713. i++;
  714. } else if (S is AssertStmt) {
  715. var skel = (AssertStmt)S;
  716. Contract.Assert(((SkeletonStatement)cur).ConditionOmitted);
  717. var oldAssume = oldS as PredicateStmt;
  718. if (oldAssume == null) {
  719. reporter.Error(cur.Tok, "assert template does not match inherited statement");
  720. i++;
  721. } else {
  722. // Clone the expression, but among the new assert's attributes, indicate
  723. // that this assertion is supposed to be translated into a check. That is,
  724. // it is not allowed to be just assumed in the translation, despite the fact
  725. // that the condition is inherited.
  726. var e = CloneExpr(oldAssume.Expr);
  727. body.Add(new AssertStmt(skel.Tok, e, new Attributes("prependAssertToken", new List<Attributes.Argument>(), null)));
  728. i++; j++;
  729. }
  730. } else if (S is IfStmt) {
  731. var skel = (IfStmt)S;
  732. Contract.Assert(((SkeletonStatement)cur).ConditionOmitted);
  733. var oldIf = oldS as IfStmt;
  734. if (oldIf == null) {
  735. reporter.Error(cur.Tok, "if-statement template does not match inherited statement");
  736. i++;
  737. } else {
  738. var resultingThen = MergeBlockStmt(skel.Thn, oldIf.Thn);
  739. var resultingElse = MergeElse(skel.Els, oldIf.Els);
  740. var r = new IfStmt(skel.Tok, skel.Guard, resultingThen, resultingElse);
  741. body.Add(r);
  742. i++; j++;
  743. }
  744. } else if (S is WhileStmt) {
  745. var skel = (WhileStmt)S;
  746. var oldWhile = oldS as WhileStmt;
  747. if (oldWhile == null) {
  748. reporter.Error(cur.Tok, "while-statement template does not match inherited statement");
  749. i++;
  750. } else {
  751. Expression guard;
  752. if (((SkeletonStatement)cur).ConditionOmitted) {
  753. guard = CloneExpr(oldWhile.Guard);
  754. } else {
  755. if (oldWhile.Guard != null) {
  756. reporter.Error(skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard");
  757. }
  758. guard = skel.Guard;
  759. }
  760. // Note, if the loop body is omitted in the skeleton, the parser will have set the loop body to an empty block,
  761. // which has the same merging behavior.
  762. var r = MergeWhileStmt(skel, oldWhile, guard);
  763. body.Add(r);
  764. i++; j++;
  765. }
  766. } else {
  767. Contract.Assume(false); // unexpected skeleton statement
  768. }
  769. } else if (cur is AssertStmt) {
  770. MergeAddStatement(cur, body);
  771. i++;
  772. } else if (cur is VarDeclStmt) {
  773. var cNew = (VarDeclStmt)cur;
  774. var cOld = oldS as VarDeclStmt;
  775. if (cOld != null && cNew.Lhss.Count == 1 && cOld.Lhss.Count == 1 && cNew.Lhss[0].Name == cOld.Lhss[0].Name && cOld.Update == null) {
  776. // Note, we allow switching between ghost and non-ghost, since that seems unproblematic.
  777. // Go ahead with the merge:
  778. body.Add(cNew);
  779. i++; j++;
  780. } else {
  781. MergeAddStatement(cur, body);
  782. i++;
  783. }
  784. } else if (cur is IfStmt) {
  785. var cNew = (IfStmt)cur;
  786. var cOld = oldS as IfStmt;
  787. if (cOld != null && cOld.Guard == null) {
  788. var r = new IfStmt(cNew.Tok, cNew.Guard, MergeBlockStmt(cNew.Thn, cOld.Thn), MergeElse(cNew.Els, cOld.Els));
  789. body.Add(r);
  790. i++; j++;
  791. } else {
  792. MergeAddStatement(cur, body);
  793. i++;
  794. }
  795. } else if (cur is WhileStmt) {
  796. var cNew = (WhileStmt)cur;
  797. var cOld = oldS as WhileStmt;
  798. if (cOld != null && cOld.Guard == null) {
  799. var r = MergeWhileStmt(cNew, cOld, cNew.Guard);
  800. body.Add(r);
  801. i++; j++;
  802. } else {
  803. MergeAddStatement(cur, body);
  804. i++;
  805. }
  806. } else {
  807. MergeAddStatement(cur, body);
  808. i++;
  809. }
  810. }
  811. }
  812. // implement the implicit "...;" at the end of each block statement skeleton
  813. for (; j < oldStmt.Body.Count; j++) {
  814. body.Add(CloneStmt(oldStmt.Body[j]));
  815. }
  816. return new BlockStmt(skeleton.Tok, body);
  817. }
  818. bool PotentialMatch(Statement nxt, Statement other) {
  819. Contract.Requires(!(nxt is SkeletonStatement) || ((SkeletonStatement)nxt).S != null); // nxt is not "...;"
  820. Contract.Requires(other != null);
  821. if (nxt is SkeletonStatement) {
  822. var S = ((SkeletonStatement)nxt).S;
  823. if (S is AssertStmt) {
  824. return other is PredicateStmt;
  825. } else if (S is IfStmt) {
  826. return other is IfStmt;
  827. } else if (S is WhileStmt) {
  828. return other is WhileStmt;
  829. } else {
  830. Contract.Assume(false); // unexpected skeleton
  831. }
  832. } else if (nxt is IfStmt) {
  833. var oth = other as IfStmt;
  834. return oth != null && oth.Guard == null;
  835. } else if (nxt is WhileStmt) {
  836. var oth = other as WhileStmt;
  837. return oth != null && oth.Guard == null;
  838. }
  839. // not a potential match
  840. return false;
  841. }
  842. WhileStmt MergeWhileStmt(WhileStmt cNew, WhileStmt cOld, Expression guard) {
  843. Contract.Requires(cNew != null);
  844. Contract.Requires(cOld != null);
  845. // Note, the parser produces errors if there are any decreases or modifies clauses (and it creates
  846. // the Specification structures with a null list).
  847. Contract.Assume(cNew.Decreases.Expressions == null);
  848. Contract.Assume(cNew.Mod.Expressions == null);
  849. var invs = cOld.Invariants.ConvertAll(CloneMayBeFreeExpr);
  850. invs.AddRange(cNew.Invariants);
  851. var r = new WhileStmt(cNew.Tok, guard, invs, CloneSpecExpr(cOld.Decreases), CloneSpecFrameExpr(cOld.Mod), MergeBlockStmt(cNew.Body, cOld.Body));
  852. return r;
  853. }
  854. Statement MergeElse(Statement skeleton, Statement oldStmt) {
  855. Contract.Requires(skeleton == null || skeleton is BlockStmt || skeleton is IfStmt);
  856. Contract.Requires(oldStmt == null || oldStmt is BlockStmt || oldStmt is IfStmt);
  857. if (skeleton == null) {
  858. return CloneStmt(oldStmt);
  859. } else if (skeleton is IfStmt) {
  860. // wrap a block statement around the if statement
  861. skeleton = new BlockStmt(skeleton.Tok, new List<Statement>() { skeleton });
  862. }
  863. if (oldStmt == null) {
  864. // make it into an empty block statement
  865. oldStmt = new BlockStmt(skeleton.Tok, new List<Statement>());
  866. } else if (oldStmt is IfStmt) {
  867. // wrap a block statement around the if statement
  868. oldStmt = new BlockStmt(oldStmt.Tok, new List<Statement>() { oldStmt });
  869. }
  870. Contract.Assert(skeleton is BlockStmt && oldStmt is BlockStmt);
  871. return MergeBlockStmt((BlockStmt)skeleton, (BlockStmt)oldStmt);
  872. }
  873. /// <summary>
  874. /// Add "s" to "stmtList", but complain if "s" contains further occurrences of "...", if "s" assigns to a
  875. /// variable that was not declared in the refining module, or if "s" has some control flow that jumps to a
  876. /// place outside "s".
  877. /// </summary>
  878. void MergeAddStatement(Statement s, List<Statement> stmtList) {
  879. Contract.Requires(s != null);
  880. Contract.Requires(stmtList != null);
  881. var prevErrorCount = reporter.ErrorCount;
  882. CheckIsOkayNewStatement(s, new Stack<string>(), 0);
  883. if (reporter.ErrorCount == prevErrorCount) {
  884. stmtList.Add(s);
  885. }
  886. }
  887. /// <summary>
  888. /// See comment on MergeAddStatement.
  889. /// </summary>
  890. void CheckIsOkayNewStatement(Statement s, Stack<string> labels, int loopLevels) {
  891. Contract.Requires(s != null);
  892. Contract.Requires(labels != null);
  893. Contract.Requires(0 <= loopLevels);
  894. for (LabelNode n = s.Labels; n != null; n = n.Next) {
  895. labels.Push(n.Label);
  896. }
  897. if (s is SkeletonStatement) {
  898. reporter.Error(s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced");
  899. } else if (s is ReturnStmt) {
  900. reporter.Error(s, "return statements are not allowed in skeletons");
  901. } else if (s is BreakStmt) {
  902. var b = (BreakStmt)s;
  903. if (b.TargetLabel != null ? !labels.Contains(b.TargetLabel) : loopLevels < b.BreakCount) {
  904. reporter.Error(s, "break statement in skeleton is not allowed to break outside the skeleton fragment");
  905. }
  906. } else if (s is AssignStmt) {
  907. // TODO: To be a refinement automatically (that is, without any further verification), only variables and fields defined
  908. // in this module are allowed. This needs to be checked. If the LHS refers to an l-value that was not declared within
  909. // this module, then either an error should be reported or the Translator needs to know to translate new proof obligations.
  910. } else {
  911. if (s is WhileStmt || s is AlternativeLoopStmt) {
  912. loopLevels++;
  913. }
  914. foreach (var ss in s.SubStatements) {
  915. CheckIsOkayNewStatement(ss, labels, loopLevels);
  916. }
  917. }
  918. for (LabelNode n = s.Labels; n != null; n = n.Next) {
  919. labels.Pop();
  920. }
  921. }
  922. // ---------------------- additional methods -----------------------------------------------------------------------------
  923. public static bool ContainsChange(Expression expr, ModuleDecl m) {
  924. Contract.Requires(expr != null);
  925. Contract.Requires(m != null);
  926. if (expr is FunctionCallExpr) {
  927. var e = (FunctionCallExpr)expr;
  928. if (e.Function.EnclosingClass.Module == m) {
  929. var p = e.Function as Predicate;
  930. if (p != null && p.BodyIsExtended) {
  931. return true;
  932. }
  933. }
  934. }
  935. foreach (var ee in expr.SubExpressions) {
  936. if (ContainsChange(ee, m)) {
  937. return true;
  938. }
  939. }
  940. return false;
  941. }
  942. }
  943. }