From 85ffcd8f1392bf871e585fe8efb60e38bfdb2f72 Mon Sep 17 00:00:00 2001 From: tabarbe Date: Fri, 13 Aug 2010 00:43:11 +0000 Subject: Boogie: Renaming VCExpr sources in preparation for port commit --- Source/VCExpr/BigLiteralAbstracter.cs | 198 +++++ Source/VCExpr/BigLiteralAbstracter.ssc | 198 ----- Source/VCExpr/Boogie2VCExpr.cs | 865 ++++++++++++++++++ Source/VCExpr/Boogie2VCExpr.ssc | 865 ------------------ Source/VCExpr/Clustering.cs | 449 ++++++++++ Source/VCExpr/Clustering.ssc | 449 ---------- Source/VCExpr/LetBindingSorter.cs | 135 +++ Source/VCExpr/LetBindingSorter.ssc | 135 --- Source/VCExpr/NameClashResolver.cs | 137 +++ Source/VCExpr/NameClashResolver.ssc | 137 --- Source/VCExpr/SimplifyLikeLineariser.cs | 844 ++++++++++++++++++ Source/VCExpr/SimplifyLikeLineariser.ssc | 844 ------------------ Source/VCExpr/TermFormulaFlattening.cs | 222 +++++ Source/VCExpr/TermFormulaFlattening.ssc | 222 ----- Source/VCExpr/TypeErasure.cs | 1176 ++++++++++++++++++++++++ Source/VCExpr/TypeErasure.ssc | 1176 ------------------------ Source/VCExpr/TypeErasureArguments.cs | 626 +++++++++++++ Source/VCExpr/TypeErasureArguments.ssc | 626 ------------- Source/VCExpr/TypeErasurePremisses.cs | 1080 ++++++++++++++++++++++ Source/VCExpr/TypeErasurePremisses.ssc | 1080 ---------------------- Source/VCExpr/VCExpr.csproj | 145 +++ Source/VCExpr/VCExpr.sscproj | 145 --- Source/VCExpr/VCExprAST.cs | 1424 ++++++++++++++++++++++++++++++ Source/VCExpr/VCExprAST.ssc | 1424 ------------------------------ Source/VCExpr/VCExprASTPrinter.cs | 247 ++++++ Source/VCExpr/VCExprASTPrinter.ssc | 247 ------ Source/VCExpr/VCExprASTVisitors.cs | 1006 +++++++++++++++++++++ Source/VCExpr/VCExprASTVisitors.ssc | 1006 --------------------- 28 files changed, 8554 insertions(+), 8554 deletions(-) create mode 100644 Source/VCExpr/BigLiteralAbstracter.cs delete mode 100644 Source/VCExpr/BigLiteralAbstracter.ssc create mode 100644 Source/VCExpr/Boogie2VCExpr.cs delete mode 100644 Source/VCExpr/Boogie2VCExpr.ssc create mode 100644 Source/VCExpr/Clustering.cs delete mode 100644 Source/VCExpr/Clustering.ssc create mode 100644 Source/VCExpr/LetBindingSorter.cs delete mode 100644 Source/VCExpr/LetBindingSorter.ssc create mode 100644 Source/VCExpr/NameClashResolver.cs delete mode 100644 Source/VCExpr/NameClashResolver.ssc create mode 100644 Source/VCExpr/SimplifyLikeLineariser.cs delete mode 100644 Source/VCExpr/SimplifyLikeLineariser.ssc create mode 100644 Source/VCExpr/TermFormulaFlattening.cs delete mode 100644 Source/VCExpr/TermFormulaFlattening.ssc create mode 100644 Source/VCExpr/TypeErasure.cs delete mode 100644 Source/VCExpr/TypeErasure.ssc create mode 100644 Source/VCExpr/TypeErasureArguments.cs delete mode 100644 Source/VCExpr/TypeErasureArguments.ssc create mode 100644 Source/VCExpr/TypeErasurePremisses.cs delete mode 100644 Source/VCExpr/TypeErasurePremisses.ssc create mode 100644 Source/VCExpr/VCExpr.csproj delete mode 100644 Source/VCExpr/VCExpr.sscproj create mode 100644 Source/VCExpr/VCExprAST.cs delete mode 100644 Source/VCExpr/VCExprAST.ssc create mode 100644 Source/VCExpr/VCExprASTPrinter.cs delete mode 100644 Source/VCExpr/VCExprASTPrinter.ssc create mode 100644 Source/VCExpr/VCExprASTVisitors.cs delete mode 100644 Source/VCExpr/VCExprASTVisitors.ssc diff --git a/Source/VCExpr/BigLiteralAbstracter.cs b/Source/VCExpr/BigLiteralAbstracter.cs new file mode 100644 index 00000000..fac34a8d --- /dev/null +++ b/Source/VCExpr/BigLiteralAbstracter.cs @@ -0,0 +1,198 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// Code for replacing large integer literals in VCExpr with +// constants. This is necessary for Simplify, which cannot deal with +// literals larger than 32 bits + +namespace Microsoft.Boogie.VCExprAST +{ + + public class BigLiteralAbstracter : MutatingVCExprVisitor, ICloneable { + + public BigLiteralAbstracter(VCExpressionGenerator! gen) { + base(gen); + DummyVar = gen.Variable("x", Type.Int); + IncAxioms = new List (); + Literals = new List> (); + } + + private BigLiteralAbstracter(BigLiteralAbstracter! abstracter) { + base(abstracter.Gen); + DummyVar = abstracter.DummyVar; + IncAxioms = new List (abstracter.IncAxioms); + Literals = new List> (abstracter.Literals); + } + + public Object! Clone() { + return new BigLiteralAbstracter(this); + } + + private static readonly BigNum ConstantDistance = BigNum.FromLong(100000); + private static readonly BigNum NegConstantDistance = BigNum.FromLong(-100000); + // distance twice plus one + private static readonly BigNum ConstantDistanceTPO = BigNum.FromLong(200001); + private static readonly BigNum ConstantDistancePO = BigNum.FromLong(100001); + + public VCExpr! Abstract(VCExpr! expr) { + return Mutate(expr, true); + } + + //////////////////////////////////////////////////////////////////////////// + + // list in which axioms are incrementally collected + private readonly List! IncAxioms; + + private void AddAxiom(VCExpr! axiom) { + IncAxioms.Add(axiom); + } + + // Return all axioms that were added since the last time NewAxioms + // was called + public VCExpr! GetNewAxioms() { + VCExpr! res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms); + IncAxioms.Clear(); + return res; + } + + //////////////////////////////////////////////////////////////////////////// + + // All named integer literals known to the visitor, in ascending + // order. Such literals are always positive, and the distance + // between two literals is always more than ConstantDistance. + private readonly List>! Literals; + + private class EntryComparerC : IComparer> { + public int Compare(KeyValuePair a, + KeyValuePair b) { + return a.Key.CompareTo(b.Key); + } + } + + private static readonly EntryComparerC EntryComparer = new EntryComparerC (); + + // variable used when searching for entries in the literal list + private readonly VCExprVar! DummyVar; + + //////////////////////////////////////////////////////////////////////////// + + // Construct an expression to represent the given (large) integer + // literal. Constants are defined and axiomatised if necessary + private VCExpr! Represent(BigNum lit) + requires NegConstantDistance > lit || lit > ConstantDistance; { + + if (lit.IsNegative) + return Gen.Function(VCExpressionGenerator.SubOp, + Gen.Integer(BigNum.ZERO), RepresentPos(lit.Neg)); + else + return RepresentPos(lit); + } + + private VCExpr! RepresentPos(BigNum lit) + requires lit > ConstantDistance; { + + int index = GetIndexFor(lit); + if (index >= 0) + // precise match + return Literals[index].Value; + + // check whether a constant is defined that is at most + // ConstantDistance away from lit + index = ~index; + VCExpr res = null; + BigNum resDistance = ConstantDistancePO; + + if (index > 0) { + BigNum dist = lit - Literals[index - 1].Key; + if (dist < resDistance) { + resDistance = dist; + res = Gen.Function(VCExpressionGenerator.AddOp, + Literals[index - 1].Value, Gen.Integer(dist)); + } + } + + if (index < Literals.Count) { + BigNum dist = Literals[index].Key - lit; + if (dist < resDistance) { + resDistance = dist; + res = Gen.Function(VCExpressionGenerator.SubOp, + Literals[index].Value, Gen.Integer(dist)); + } + } + + if (res != null) + return res; + + // otherwise, define a new constant to represent this literal + return AddConstantFor(lit); + } + + private VCExpr! AddConstantFor(BigNum lit) + requires lit > ConstantDistance; { + + VCExprVar! res = Gen.Variable("int#" + lit, Type.Int); + int index = GetIndexFor(lit); + assert index < 0; + index = ~index; + + Literals.Insert(index, new KeyValuePair(lit, res)); + + // relate the new constant to the predecessor and successor + if (index > 0) + DefineRelationship(Literals[index - 1].Value, Literals[index - 1].Key, + res, lit); + else + DefineRelationship(Gen.Integer(BigNum.ZERO), BigNum.ZERO, res, lit); + + if (index < Literals.Count - 1) + DefineRelationship(res, lit, + Literals[index + 1].Value, Literals[index + 1].Key); + + return res; + } + + private void DefineRelationship(VCExpr! aExpr, BigNum aValue, + VCExpr! bExpr, BigNum bValue) + requires aValue < bValue; { + + BigNum dist = bValue - aValue; + VCExpr! distExpr = Gen.Function(VCExpressionGenerator.SubOp, bExpr, aExpr); + if (dist <= ConstantDistanceTPO) + // constants that are sufficiently close to each other are put + // into a precise relationship + AddAxiom(Gen.Eq(distExpr, Gen.Integer(dist))); + else + AddAxiom(Gen.Function(VCExpressionGenerator.GtOp, + distExpr, Gen.Integer(ConstantDistanceTPO))); + } + + private int GetIndexFor(BigNum lit) { + return Literals.BinarySearch(new KeyValuePair + (lit, DummyVar), + EntryComparer); + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprLiteral! node, bool arg) { + VCExprIntLit intLit = node as VCExprIntLit; + if (intLit != null) { + if (NegConstantDistance > intLit.Val || intLit.Val > ConstantDistance) + return Represent(intLit.Val); + } + return node; + } + + } + +} \ No newline at end of file diff --git a/Source/VCExpr/BigLiteralAbstracter.ssc b/Source/VCExpr/BigLiteralAbstracter.ssc deleted file mode 100644 index fac34a8d..00000000 --- a/Source/VCExpr/BigLiteralAbstracter.ssc +++ /dev/null @@ -1,198 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// Code for replacing large integer literals in VCExpr with -// constants. This is necessary for Simplify, which cannot deal with -// literals larger than 32 bits - -namespace Microsoft.Boogie.VCExprAST -{ - - public class BigLiteralAbstracter : MutatingVCExprVisitor, ICloneable { - - public BigLiteralAbstracter(VCExpressionGenerator! gen) { - base(gen); - DummyVar = gen.Variable("x", Type.Int); - IncAxioms = new List (); - Literals = new List> (); - } - - private BigLiteralAbstracter(BigLiteralAbstracter! abstracter) { - base(abstracter.Gen); - DummyVar = abstracter.DummyVar; - IncAxioms = new List (abstracter.IncAxioms); - Literals = new List> (abstracter.Literals); - } - - public Object! Clone() { - return new BigLiteralAbstracter(this); - } - - private static readonly BigNum ConstantDistance = BigNum.FromLong(100000); - private static readonly BigNum NegConstantDistance = BigNum.FromLong(-100000); - // distance twice plus one - private static readonly BigNum ConstantDistanceTPO = BigNum.FromLong(200001); - private static readonly BigNum ConstantDistancePO = BigNum.FromLong(100001); - - public VCExpr! Abstract(VCExpr! expr) { - return Mutate(expr, true); - } - - //////////////////////////////////////////////////////////////////////////// - - // list in which axioms are incrementally collected - private readonly List! IncAxioms; - - private void AddAxiom(VCExpr! axiom) { - IncAxioms.Add(axiom); - } - - // Return all axioms that were added since the last time NewAxioms - // was called - public VCExpr! GetNewAxioms() { - VCExpr! res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms); - IncAxioms.Clear(); - return res; - } - - //////////////////////////////////////////////////////////////////////////// - - // All named integer literals known to the visitor, in ascending - // order. Such literals are always positive, and the distance - // between two literals is always more than ConstantDistance. - private readonly List>! Literals; - - private class EntryComparerC : IComparer> { - public int Compare(KeyValuePair a, - KeyValuePair b) { - return a.Key.CompareTo(b.Key); - } - } - - private static readonly EntryComparerC EntryComparer = new EntryComparerC (); - - // variable used when searching for entries in the literal list - private readonly VCExprVar! DummyVar; - - //////////////////////////////////////////////////////////////////////////// - - // Construct an expression to represent the given (large) integer - // literal. Constants are defined and axiomatised if necessary - private VCExpr! Represent(BigNum lit) - requires NegConstantDistance > lit || lit > ConstantDistance; { - - if (lit.IsNegative) - return Gen.Function(VCExpressionGenerator.SubOp, - Gen.Integer(BigNum.ZERO), RepresentPos(lit.Neg)); - else - return RepresentPos(lit); - } - - private VCExpr! RepresentPos(BigNum lit) - requires lit > ConstantDistance; { - - int index = GetIndexFor(lit); - if (index >= 0) - // precise match - return Literals[index].Value; - - // check whether a constant is defined that is at most - // ConstantDistance away from lit - index = ~index; - VCExpr res = null; - BigNum resDistance = ConstantDistancePO; - - if (index > 0) { - BigNum dist = lit - Literals[index - 1].Key; - if (dist < resDistance) { - resDistance = dist; - res = Gen.Function(VCExpressionGenerator.AddOp, - Literals[index - 1].Value, Gen.Integer(dist)); - } - } - - if (index < Literals.Count) { - BigNum dist = Literals[index].Key - lit; - if (dist < resDistance) { - resDistance = dist; - res = Gen.Function(VCExpressionGenerator.SubOp, - Literals[index].Value, Gen.Integer(dist)); - } - } - - if (res != null) - return res; - - // otherwise, define a new constant to represent this literal - return AddConstantFor(lit); - } - - private VCExpr! AddConstantFor(BigNum lit) - requires lit > ConstantDistance; { - - VCExprVar! res = Gen.Variable("int#" + lit, Type.Int); - int index = GetIndexFor(lit); - assert index < 0; - index = ~index; - - Literals.Insert(index, new KeyValuePair(lit, res)); - - // relate the new constant to the predecessor and successor - if (index > 0) - DefineRelationship(Literals[index - 1].Value, Literals[index - 1].Key, - res, lit); - else - DefineRelationship(Gen.Integer(BigNum.ZERO), BigNum.ZERO, res, lit); - - if (index < Literals.Count - 1) - DefineRelationship(res, lit, - Literals[index + 1].Value, Literals[index + 1].Key); - - return res; - } - - private void DefineRelationship(VCExpr! aExpr, BigNum aValue, - VCExpr! bExpr, BigNum bValue) - requires aValue < bValue; { - - BigNum dist = bValue - aValue; - VCExpr! distExpr = Gen.Function(VCExpressionGenerator.SubOp, bExpr, aExpr); - if (dist <= ConstantDistanceTPO) - // constants that are sufficiently close to each other are put - // into a precise relationship - AddAxiom(Gen.Eq(distExpr, Gen.Integer(dist))); - else - AddAxiom(Gen.Function(VCExpressionGenerator.GtOp, - distExpr, Gen.Integer(ConstantDistanceTPO))); - } - - private int GetIndexFor(BigNum lit) { - return Literals.BinarySearch(new KeyValuePair - (lit, DummyVar), - EntryComparer); - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprLiteral! node, bool arg) { - VCExprIntLit intLit = node as VCExprIntLit; - if (intLit != null) { - if (NegConstantDistance > intLit.Val || intLit.Val > ConstantDistance) - return Represent(intLit.Val); - } - return node; - } - - } - -} \ No newline at end of file diff --git a/Source/VCExpr/Boogie2VCExpr.cs b/Source/VCExpr/Boogie2VCExpr.cs new file mode 100644 index 00000000..df966c2d --- /dev/null +++ b/Source/VCExpr/Boogie2VCExpr.cs @@ -0,0 +1,865 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// A translator from the Boogie AST to the VCExpr AST. +// This was previously realised in the methods AbsyExpr.VCView + +namespace Microsoft.Boogie.VCExprAST +{ + using Microsoft.Boogie; + + public class VCGenerationOptions { + private readonly List! SupportedProverCommands; + + public bool IsProverCommandSupported(string! kind) + { + return SupportedProverCommands.Contains(kind); + } + + public bool IsAnyProverCommandSupported(string! kinds) + { + if (kinds.IndexOf(',') < 0) { + return IsProverCommandSupported(kinds); + } else { + return exists{string k in kinds.Split(',', ' '); IsProverCommandSupported(k)}; + } + } + + public VCGenerationOptions(List! supportedProverCommands) { + this.SupportedProverCommands = supportedProverCommands; + } + } + + public delegate VCExpr! CodeExprConverter(CodeExpr! codeExpr, Hashtable/**/! blockVariables, List! bindings); + + public class Boogie2VCExprTranslator : StandardVisitor, ICloneable { + // Stack on which the various Visit-methods put the result of the translation + private readonly Stack! SubExpressions = new Stack (); + + private void Push(VCExpr! expr) { + SubExpressions.Push(expr); + } + + private VCExpr! Pop() { + return SubExpressions.Pop(); + } + + public VCExpr! Translate(Expr! expr) { + this.Visit(expr); + return Pop(); + } + + public List! Translate(ExprSeq! exprs) { + List! res = new List (); + foreach(Expr e in exprs) + res.Add(Translate((!)e)); + return res; + } + + /////////////////////////////////////////////////////////////////////////////// + + internal readonly VCExpressionGenerator! Gen; + + public Boogie2VCExprTranslator(VCExpressionGenerator! gen, + VCGenerationOptions! genOptions) { + this.Gen = gen; + this.GenerationOptions = genOptions; + UnboundVariables = new VariableMapping (); + BoundVariables = new VariableMapping (); + Formals = new VariableMapping (); + } + + private Boogie2VCExprTranslator(Boogie2VCExprTranslator! tl) { + this.Gen = tl.Gen; + this.GenerationOptions = tl.GenerationOptions; + UnboundVariables = + (VariableMapping)tl.UnboundVariables.Clone(); + BoundVariables = new VariableMapping (); + Formals = new VariableMapping (); + } + + public object! Clone() { + return new Boogie2VCExprTranslator(this); + } + + private IAppliableTranslator IAppTranslatorAttr = null; + private IAppliableTranslator! IAppTranslator { get { + if (IAppTranslatorAttr == null) + IAppTranslatorAttr = new IAppliableTranslator (this); + return IAppTranslatorAttr; + } } + + /////////////////////////////////////////////////////////////////////////////// + // Class for handling occurring variables + + private class VariableMapping : ICloneable { + private readonly List!>! Mapping; + + public VariableMapping() { + List!>! mapping = + new List!> (); + mapping.Add(new Dictionary ()); + this.Mapping = mapping; + } + + private VariableMapping(VariableMapping! vm) { + List!>! mapping = + new List!> (); + foreach (Dictionary! d in vm.Mapping) + mapping.Add(new Dictionary (d)); + this.Mapping = mapping; + } + + public object! Clone() { + return new VariableMapping (this); + } + + public void PushScope() { + Mapping.Add(new Dictionary ()); + } + + public void PopScope() { + assume Mapping.Count > 0; + Mapping.RemoveAt(Mapping.Count - 1); + } + + public void Bind(VarKind! boogieVar, VCExprVar! vcExprVar) + requires !Contains(boogieVar); { + Mapping[Mapping.Count - 1].Add(boogieVar, vcExprVar); + } + + public VCExprVar! Lookup(VarKind! boogieVar) { + VCExprVar res = LookupHelp(boogieVar); + assume res != null; + return res; + } + + [Pure] + public bool Contains(VarKind! boogieVar) { + return LookupHelp(boogieVar) != null; + } + + public bool TryGetValue(VarKind! boogieVar, out VCExprVar res) { + res = LookupHelp(boogieVar); + return res != null; + } + + [Pure] + private VCExprVar LookupHelp(VarKind! boogieVar) { + VCExprVar res; + foreach (Dictionary! d in Mapping) { + if (d.TryGetValue(boogieVar, out res)) + return res; + } + return null; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + + private readonly VariableMapping! UnboundVariables; + private readonly VariableMapping! BoundVariables; + // used when translating the bodies of function expansions + private readonly VariableMapping! Formals; + + internal void PushBoundVariableScope() { + BoundVariables.PushScope(); + } + internal void PopBoundVariableScope() { + BoundVariables.PopScope(); + } + + internal void PushFormalsScope() { + Formals.PushScope(); + } + internal void PopFormalsScope() { + Formals.PopScope(); + } + + public VCExprVar! BindVariable(Variable! boogieVar) { + if (boogieVar is BoundVariable) { + VCExprVar! newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); + BoundVariables.Bind((BoundVariable)boogieVar, newVar); + return newVar; + } else if (boogieVar is Formal) { + VCExprVar! newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); + Formals.Bind((Formal)boogieVar, newVar); + return newVar; + } else { + // only bound variables and formals are declared explicitly + assert false; + } + } + + public VCExprVar! LookupVariable(Variable! boogieVar) { + + BoundVariable bv = boogieVar as BoundVariable; + if (bv != null) { + return BoundVariables.Lookup(bv); + } + VCExprVar res; + Formal fml = boogieVar as Formal; + if (fml != null && Formals.TryGetValue(fml, out res)) + return (!)res; + + // global variables, local variables, incarnations, etc. are + // bound the first time they occur + if (!UnboundVariables.TryGetValue(boogieVar, out res)) { + res = new VCExprVar (boogieVar.Name, boogieVar.TypedIdent.Type); + UnboundVariables.Bind(boogieVar, res); + } + return (!)res; + } + + /////////////////////////////////////////////////////////////////////////////////// + + internal readonly VCGenerationOptions! GenerationOptions; + + /////////////////////////////////////////////////////////////////////////////////// + + public override LiteralExpr! VisitLiteralExpr(LiteralExpr! node) { + Push(TranslateLiteralExpr(node)); + return node; + } + private VCExpr! TranslateLiteralExpr(LiteralExpr! node) { + if ( node.Val is bool ) + { + bool b = (bool) node.Val; + if ( b ) { + return VCExpressionGenerator.True; + } else { + return VCExpressionGenerator.False; + } + } + else if ( node.Val is BigNum ) + { + return Gen.Integer(node.asBigNum); + } + else if ( node.Val is BvConst ) + { + return Gen.Bitvector((BvConst)node.Val); + } + else + { + System.Diagnostics.Debug.Assert(false, "unknown kind of literal " + node.tok.ToString()); + assert false; + } + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override AIVariableExpr! VisitAIVariableExpr(AIVariableExpr! node) + { + assert false; + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override Expr! VisitIdentifierExpr(IdentifierExpr! node) { + assume node.Decl != null; // the expression has to be resolved + Push(LookupVariable(node.Decl)); + return node; + } + + /////////////////////////////////////////////////////////////////////////////////// + + // Because of our scheme for numbering incarnations of variables, the pre-state + // value of a variable x is always just "x". (The first update to it in a method + // causes it to become "x0". So we just remove old expressions with a visitor + // before transforming it into a VCExpr. + public override Expr! VisitOldExpr(OldExpr! node) + { + assert false; + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override Expr! VisitNAryExpr(NAryExpr! node) + { + Push(TranslateNAryExpr(node)); + return node; + } + + private VCExpr! TranslateNAryExpr(NAryExpr! node) { + int n = node.Args.Length; + List! vcs = new List (n); + for(int i = 0; i < n; i++) + { + vcs.Add(Translate((!)node.Args[i])); + } + + if (node.Type == null) { + System.Console.WriteLine("*** type is null for {0}", node); + assert false; + } + + return IAppTranslator.Translate(node.Fun, node.Type, vcs, + ToList((!)node.TypeParameters)); + } + + + private static List! EMPTY_TYPE_LIST = new List (); + + private List! ToList(TypeParamInstantiation! insts) { + if (insts.FormalTypeParams.Count == 0) + return EMPTY_TYPE_LIST; + + List! typeArgs = new List (); + foreach (TypeVariable! var in insts.FormalTypeParams) + typeArgs.Add(insts[var]); + return typeArgs; + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override QuantifierExpr! VisitQuantifierExpr(QuantifierExpr! node) { + Push(TranslateQuantifierExpr(node)); + return node; + } + + public override ExistsExpr! VisitExistsExpr(ExistsExpr! node) + { + node = (ExistsExpr) this.VisitQuantifierExpr(node); + return node; + } + + public override ForallExpr! VisitForallExpr(ForallExpr! node) + { + node = (ForallExpr) this.VisitQuantifierExpr(node); + return node; + } + + private VCExpr! TranslateQuantifierExpr(QuantifierExpr! node) + { + List! typeParams = new List (); + foreach (TypeVariable! v in node.TypeParameters) + typeParams.Add(v); + + PushBoundVariableScope(); + + List! boundVars = new List (); + foreach (Variable! v in node.Dummies) + boundVars.Add(BindVariable(v)); + + try { + List! triggers = TranslateTriggers(node.Triggers); + VCExpr! body = Translate(node.Body); + VCQuantifierInfos! infos = GenerateQuantifierInfos(node); + + Quantifier quan; + if (node is ForallExpr) + quan = Quantifier.ALL; + else if (node is ExistsExpr) + quan = Quantifier.EX; + else + assert false; + + return Gen.Quantify(quan, typeParams, boundVars, triggers, infos, body); + } finally { + PopBoundVariableScope(); + } + } + + private List! TranslateTriggers(Trigger node) + { + List! res = new List (); + Trigger curTrigger = node; + while (curTrigger != null) { + res.Add(Gen.Trigger(curTrigger.Pos, Translate(curTrigger.Tr))); + curTrigger = curTrigger.Next; + } + return res; + } + + private VCQuantifierInfos! GenerateQuantifierInfos(QuantifierExpr! node) { + string qid = getQidNameFromQKeyValue(node.Dummies, node.Attributes); + return new VCQuantifierInfos(qid, node.SkolemId, false, node.Attributes); + } + + private string getQidNameFromQKeyValue(VariableSeq! vars, QKeyValue attributes) { + // Check for a 'qid, name' pair in keyvalues + string qid = QKeyValue.FindStringAttribute(attributes, "qid"); + if (qid == null && vars.Length != 0){ + // generate default name (line:column position in .bpl file) + Variable v = vars[0]; + assert v != null; // Rustan's claim! + // Include the first 8 characters of the filename in QID (helpful in case we use /concat) + // We limit it to 8, so the SX file doesn't grow too big, and who on earth would need + // more than 8 characters in a filename anyways. + int max = 8; + StringBuilder buf = new StringBuilder(max + 20); + string filename = v.tok.filename; + if (filename == null) filename = "unknown"; + for (int i = 0; i < filename.Length; ++i) { + if (filename[i] == '/' || filename[i] == '\\') buf.Length = 0; + if (buf.Length < max && char.IsLetterOrDigit(filename[i])) { + if (buf.Length == 0 && char.IsDigit(filename[i])) { + // Z3 does not like QID's to start with a digit, so we prepend another character + buf.Append('_'); + } + buf.Append(filename[i]); + } + } + buf.Append('.').Append(v.Line).Append(':').Append(v.Col); + qid = buf.ToString(); + } + return qid; + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override BvExtractExpr! VisitBvExtractExpr(BvExtractExpr! node) + { + Push(TranslateBvExtractExpr(node)); + return node; + } + + private VCExpr! TranslateBvExtractExpr(BvExtractExpr! node) + requires node.Start <= node.End; { + VCExpr! bv = Translate(node.Bitvector); + return Gen.BvExtract(bv, ((!)node.Bitvector.Type).BvBits, node.Start, node.End); + } + + /////////////////////////////////////////////////////////////////////////////////// + + public override BvConcatExpr! VisitBvConcatExpr(BvConcatExpr! node) + { + Push(TranslateBvConcatExpr(node)); + return node; + } + + private VCExpr! TranslateBvConcatExpr(BvConcatExpr! node) { + VCExpr! bv0 = Translate(node.E0); + VCExpr! bv1 = Translate(node.E1); + return Gen.BvConcat(bv0, bv1); + } + + /////////////////////////////////////////////////////////////////////////////////// + // all the other cases should never happen + + public override Cmd! VisitAssertCmd(AssertCmd! node) + { + assert false; + } + public override Cmd! VisitAssignCmd(AssignCmd! node) + { + assert false; + } + public override Cmd! VisitAssumeCmd(AssumeCmd! node) + { + assert false; + } + public override AtomicRE! VisitAtomicRE(AtomicRE! node) + { + assert false; + } + public override Axiom! VisitAxiom(Axiom! node) + { + assert false; + } + public override Type! VisitBasicType(BasicType! node) + { + assert false; + } + public override Type! VisitBvType(BvType! node) + { + assert false; + } + public override Block! VisitBlock(Block! node) + { + assert false; + } + CodeExprConverter codeExprConverter = null; + public void SetCodeExprConverter(CodeExprConverter f){ + this.codeExprConverter = f; + } + public override Expr! VisitCodeExpr(CodeExpr! codeExpr) + { + assume codeExprConverter != null; + + Hashtable/**/ blockVariables = new Hashtable/**/(); + List bindings = new List(); + VCExpr e = codeExprConverter(codeExpr, blockVariables, bindings); + Push(e); + return codeExpr; + } + public override BlockSeq! VisitBlockSeq(BlockSeq! blockSeq) + { + assert false; + } + public override List! VisitBlockList(List! blocks) + { + assert false; + } + public override BoundVariable! VisitBoundVariable(BoundVariable! node) + { + assert false; + } + public override Cmd! VisitCallCmd(CallCmd! node) + { + assert false; + } + public override Cmd! VisitCallForallCmd(CallForallCmd! node) + { + assert false; + } + public override CmdSeq! VisitCmdSeq(CmdSeq! cmdSeq) + { + assert false; + } + public override Choice! VisitChoice(Choice! node) + { + assert false; + } + public override Cmd! VisitCommentCmd(CommentCmd! node) + { + assert false; + } + public override Constant! VisitConstant(Constant! node) + { + assert false; + } + public override CtorType! VisitCtorType(CtorType! node) + { + assert false; + } + public override Declaration! VisitDeclaration(Declaration! node) + { + assert false; + } + public override List! VisitDeclarationList(List! declarationList) + { + assert false; + } + public override DeclWithFormals! VisitDeclWithFormals(DeclWithFormals! node) + { + assert false; + } + public override Requires! VisitRequires(Requires! @requires) + { + assert false; + } + public override RequiresSeq! VisitRequiresSeq(RequiresSeq! requiresSeq) + { + assert false; + } + public override Ensures! VisitEnsures(Ensures! @ensures) + { + assert false; + } + public override EnsuresSeq! VisitEnsuresSeq(EnsuresSeq! ensuresSeq) + { + assert false; + } + public override Formal! VisitFormal(Formal! node) + { + assert false; + } + public override Function! VisitFunction(Function! node) + { + assert false; + } + public override GlobalVariable! VisitGlobalVariable(GlobalVariable! node) + { + assert false; + } + public override GotoCmd! VisitGotoCmd(GotoCmd! node) + { + assert false; + } + public override Cmd! VisitHavocCmd(HavocCmd! node) + { + assert false; + } + public override Implementation! VisitImplementation(Implementation! node) + { + assert false; + } + public override LocalVariable! VisitLocalVariable(LocalVariable! node) + { + assert false; + } + public override AssignLhs! VisitMapAssignLhs(MapAssignLhs! node) + { + assert false; + } + public override MapType! VisitMapType(MapType! node) + { + assert false; + } + public override Procedure! VisitProcedure(Procedure! node) + { + assert false; + } + public override Program! VisitProgram(Program! node) + { + assert false; + } + public override Cmd! VisitRE(RE! node) + { + assert false; + } + public override RESeq! VisitRESeq(RESeq! reSeq) + { + assert false; + } + public override ReturnCmd! VisitReturnCmd(ReturnCmd! node) + { + assert false; + } + public override ReturnExprCmd! VisitReturnExprCmd(ReturnExprCmd! node) + { + assert false; + } + public override Sequential! VisitSequential(Sequential! node) + { + assert false; + } + public override AssignLhs! VisitSimpleAssignLhs(SimpleAssignLhs! node) + { + assert false; + } + public override Cmd! VisitStateCmd(StateCmd! node) + { + assert false; + } + public override TransferCmd! VisitTransferCmd(TransferCmd! node) + { + assert false; + } + public override Trigger! VisitTrigger(Trigger! node) + { + assert false; + } + public override Type! VisitType(Type! node) + { + assert false; + } + public override TypedIdent! VisitTypedIdent(TypedIdent! node) + { + assert false; + } + public override Type! VisitTypeSynonymAnnotation(TypeSynonymAnnotation! node) + { + assert false; + } + public override Type! VisitTypeVariable(TypeVariable! node) + { + assert false; + } + public override Variable! VisitVariable(Variable! node) + { + assert false; + } + public override VariableSeq! VisitVariableSeq(VariableSeq! variableSeq) + { + assert false; + } + public override Cmd! VisitAssertEnsuresCmd(AssertEnsuresCmd! node) + { + assert false; + } + public override Cmd! VisitAssertRequiresCmd(AssertRequiresCmd! node) + { + assert false; + } + + } + + + ///////////////////////////////////////////////////////////////////////////////// + + public class IAppliableTranslator : IAppliableVisitor { + + private readonly Boogie2VCExprTranslator! BaseTranslator; + + private VCExpressionGenerator! Gen { get { + return BaseTranslator.Gen; + } } + private VCGenerationOptions! GenerationOptions { get { + return BaseTranslator.GenerationOptions; + } } + + public IAppliableTranslator(Boogie2VCExprTranslator! baseTranslator) { + this.BaseTranslator = baseTranslator; + } + + /////////////////////////////////////////////////////////////////////////////// + + private List! args = new List(); + private List! typeArgs = new List(); + + public VCExpr! Translate(IAppliable! app, Type! ty, List! args, List! typeArgs) { + + List! oldArgs = this.args; + List! oldTypeArgs = this.typeArgs; + this.args = args; + this.typeArgs = typeArgs; + VCExpr! result = app.Dispatch(this); + this.args = oldArgs; + this.typeArgs = oldTypeArgs; + return result; + } + + /////////////////////////////////////////////////////////////////////////////// + + + + public VCExpr! Visit(UnaryOperator! unaryOperator) { + assert unaryOperator.Op == UnaryOperator.Opcode.Not && this.args.Count == 1; + return Gen.Not(this.args); + } + + public VCExpr! Visit(BinaryOperator! binaryOperator) { + return TranslateBinaryOperator(binaryOperator, this.args); + } + + public VCExpr! Visit(FunctionCall! functionCall) { + return TranslateFunctionCall(functionCall, this.args, this.typeArgs); + } + + public VCExpr! Visit(MapSelect! mapSelect) { + return Gen.Select(this.args, this.typeArgs); + } + + public VCExpr! Visit(MapStore! mapStore) { + return Gen.Store(this.args, this.typeArgs); + } + + public VCExpr! Visit(TypeCoercion! typeCoercion) { + assert this.args.Count == 1; + return this.args[0]; + } + + public VCExpr! Visit(IfThenElse! ite) { + return Gen.Function(VCExpressionGenerator.IfThenElseOp, this.args); + } + + /////////////////////////////////////////////////////////////////////////////// + + private VCExpr! TranslateBinaryOperator(BinaryOperator! app, List! args) { + assert args.Count == 2; + + switch (app.Op) { + case BinaryOperator.Opcode.Add: + return Gen.Function(VCExpressionGenerator.AddOp, args); + case BinaryOperator.Opcode.Sub: + return Gen.Function(VCExpressionGenerator.SubOp, args); + case BinaryOperator.Opcode.Mul: + return Gen.Function(VCExpressionGenerator.MulOp, args); + case BinaryOperator.Opcode.Div: + return Gen.Function(VCExpressionGenerator.DivOp, args); + case BinaryOperator.Opcode.Mod: + return Gen.Function(VCExpressionGenerator.ModOp, args); + case BinaryOperator.Opcode.Eq: + case BinaryOperator.Opcode.Iff: + // we don't distinguish between equality and equivalence at this point + return Gen.Function(VCExpressionGenerator.EqOp, args); + case BinaryOperator.Opcode.Neq: + return Gen.Function(VCExpressionGenerator.NeqOp, args); + case BinaryOperator.Opcode.Lt: + return Gen.Function(VCExpressionGenerator.LtOp, args); + case BinaryOperator.Opcode.Le: + return Gen.Function(VCExpressionGenerator.LeOp, args); + case BinaryOperator.Opcode.Ge: + return Gen.Function(VCExpressionGenerator.GeOp, args); + case BinaryOperator.Opcode.Gt: + return Gen.Function(VCExpressionGenerator.GtOp, args); + case BinaryOperator.Opcode.Imp: + return Gen.Function(VCExpressionGenerator.ImpliesOp, args); + case BinaryOperator.Opcode.And: + return Gen.Function(VCExpressionGenerator.AndOp, args); + case BinaryOperator.Opcode.Or: + return Gen.Function(VCExpressionGenerator.OrOp, args); + case BinaryOperator.Opcode.Subtype: + return Gen.Function(VCExpressionGenerator.SubtypeOp, args); + default: + assert false; // unexpected binary operator + } + } + + /////////////////////////////////////////////////////////////////////////////// + + private VCExpr! TranslateFunctionCall(FunctionCall! app, + List! args, List! typeArgs) { + assert app.Func != null; // resolution must have happened + + VCExpr res = ApplyExpansion(app, args, typeArgs); + if (res != null) + return res; + + VCExprOp! functionOp = Gen.BoogieFunctionOp(app.Func); + return Gen.Function(functionOp, args, typeArgs); + } + + private VCExpr ApplyExpansion(FunctionCall! app, + List! args, List! typeArgs) { + assert app.Func != null; // resolution must have happened + + if (app.Func.doingExpansion) { + System.Console.WriteLine("*** detected expansion loop on {0}", app.Func); + return null; + } + + Expansion exp = FindExpansion(app.Func); + if (exp == null) + return null; + + VCExpr! translatedBody; + VCExprSubstitution! subst = new VCExprSubstitution(); + try { + BaseTranslator.PushFormalsScope(); + BaseTranslator.PushBoundVariableScope(); + app.Func.doingExpansion = true; + + // first bind the formals to VCExpr variables, which are later + // substituted with the actual parameters + for (int i = 0; i < exp.formals.Length; ++i) + subst[BaseTranslator.BindVariable((!)exp.formals[i])] = args[i]; + + // recursively translate the body of the expansion + translatedBody = BaseTranslator.Translate(exp.body); + } finally { + BaseTranslator.PopFormalsScope(); + BaseTranslator.PopBoundVariableScope(); + app.Func.doingExpansion = false; + } + + // substitute the formals with the actual parameters in the body + assert typeArgs.Count == exp.TypeParameters.Length; + for (int i = 0; i < typeArgs.Count; ++i) + subst[exp.TypeParameters[i]] = typeArgs[i]; + SubstitutingVCExprVisitor! substituter = new SubstitutingVCExprVisitor (Gen); + return substituter.Mutate(translatedBody, subst); + } + + private Expansion? FindExpansion(Function! func) + { + if (func.expansions == null) return null; + + Expansion? exp = null; + foreach (Expansion! e in func.expansions) { + if (e.ignore == null || !GenerationOptions.IsAnyProverCommandSupported(e.ignore)) { + if (exp == null) { + exp = e; + } else { + System.Console.WriteLine("*** more than one possible expansion for {0}", func); + return null; + } + } + } + + return exp; + } + } +} diff --git a/Source/VCExpr/Boogie2VCExpr.ssc b/Source/VCExpr/Boogie2VCExpr.ssc deleted file mode 100644 index df966c2d..00000000 --- a/Source/VCExpr/Boogie2VCExpr.ssc +++ /dev/null @@ -1,865 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// A translator from the Boogie AST to the VCExpr AST. -// This was previously realised in the methods AbsyExpr.VCView - -namespace Microsoft.Boogie.VCExprAST -{ - using Microsoft.Boogie; - - public class VCGenerationOptions { - private readonly List! SupportedProverCommands; - - public bool IsProverCommandSupported(string! kind) - { - return SupportedProverCommands.Contains(kind); - } - - public bool IsAnyProverCommandSupported(string! kinds) - { - if (kinds.IndexOf(',') < 0) { - return IsProverCommandSupported(kinds); - } else { - return exists{string k in kinds.Split(',', ' '); IsProverCommandSupported(k)}; - } - } - - public VCGenerationOptions(List! supportedProverCommands) { - this.SupportedProverCommands = supportedProverCommands; - } - } - - public delegate VCExpr! CodeExprConverter(CodeExpr! codeExpr, Hashtable/**/! blockVariables, List! bindings); - - public class Boogie2VCExprTranslator : StandardVisitor, ICloneable { - // Stack on which the various Visit-methods put the result of the translation - private readonly Stack! SubExpressions = new Stack (); - - private void Push(VCExpr! expr) { - SubExpressions.Push(expr); - } - - private VCExpr! Pop() { - return SubExpressions.Pop(); - } - - public VCExpr! Translate(Expr! expr) { - this.Visit(expr); - return Pop(); - } - - public List! Translate(ExprSeq! exprs) { - List! res = new List (); - foreach(Expr e in exprs) - res.Add(Translate((!)e)); - return res; - } - - /////////////////////////////////////////////////////////////////////////////// - - internal readonly VCExpressionGenerator! Gen; - - public Boogie2VCExprTranslator(VCExpressionGenerator! gen, - VCGenerationOptions! genOptions) { - this.Gen = gen; - this.GenerationOptions = genOptions; - UnboundVariables = new VariableMapping (); - BoundVariables = new VariableMapping (); - Formals = new VariableMapping (); - } - - private Boogie2VCExprTranslator(Boogie2VCExprTranslator! tl) { - this.Gen = tl.Gen; - this.GenerationOptions = tl.GenerationOptions; - UnboundVariables = - (VariableMapping)tl.UnboundVariables.Clone(); - BoundVariables = new VariableMapping (); - Formals = new VariableMapping (); - } - - public object! Clone() { - return new Boogie2VCExprTranslator(this); - } - - private IAppliableTranslator IAppTranslatorAttr = null; - private IAppliableTranslator! IAppTranslator { get { - if (IAppTranslatorAttr == null) - IAppTranslatorAttr = new IAppliableTranslator (this); - return IAppTranslatorAttr; - } } - - /////////////////////////////////////////////////////////////////////////////// - // Class for handling occurring variables - - private class VariableMapping : ICloneable { - private readonly List!>! Mapping; - - public VariableMapping() { - List!>! mapping = - new List!> (); - mapping.Add(new Dictionary ()); - this.Mapping = mapping; - } - - private VariableMapping(VariableMapping! vm) { - List!>! mapping = - new List!> (); - foreach (Dictionary! d in vm.Mapping) - mapping.Add(new Dictionary (d)); - this.Mapping = mapping; - } - - public object! Clone() { - return new VariableMapping (this); - } - - public void PushScope() { - Mapping.Add(new Dictionary ()); - } - - public void PopScope() { - assume Mapping.Count > 0; - Mapping.RemoveAt(Mapping.Count - 1); - } - - public void Bind(VarKind! boogieVar, VCExprVar! vcExprVar) - requires !Contains(boogieVar); { - Mapping[Mapping.Count - 1].Add(boogieVar, vcExprVar); - } - - public VCExprVar! Lookup(VarKind! boogieVar) { - VCExprVar res = LookupHelp(boogieVar); - assume res != null; - return res; - } - - [Pure] - public bool Contains(VarKind! boogieVar) { - return LookupHelp(boogieVar) != null; - } - - public bool TryGetValue(VarKind! boogieVar, out VCExprVar res) { - res = LookupHelp(boogieVar); - return res != null; - } - - [Pure] - private VCExprVar LookupHelp(VarKind! boogieVar) { - VCExprVar res; - foreach (Dictionary! d in Mapping) { - if (d.TryGetValue(boogieVar, out res)) - return res; - } - return null; - } - } - - ////////////////////////////////////////////////////////////////////////////////// - - private readonly VariableMapping! UnboundVariables; - private readonly VariableMapping! BoundVariables; - // used when translating the bodies of function expansions - private readonly VariableMapping! Formals; - - internal void PushBoundVariableScope() { - BoundVariables.PushScope(); - } - internal void PopBoundVariableScope() { - BoundVariables.PopScope(); - } - - internal void PushFormalsScope() { - Formals.PushScope(); - } - internal void PopFormalsScope() { - Formals.PopScope(); - } - - public VCExprVar! BindVariable(Variable! boogieVar) { - if (boogieVar is BoundVariable) { - VCExprVar! newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); - BoundVariables.Bind((BoundVariable)boogieVar, newVar); - return newVar; - } else if (boogieVar is Formal) { - VCExprVar! newVar = Gen.Variable(boogieVar.Name, boogieVar.TypedIdent.Type); - Formals.Bind((Formal)boogieVar, newVar); - return newVar; - } else { - // only bound variables and formals are declared explicitly - assert false; - } - } - - public VCExprVar! LookupVariable(Variable! boogieVar) { - - BoundVariable bv = boogieVar as BoundVariable; - if (bv != null) { - return BoundVariables.Lookup(bv); - } - VCExprVar res; - Formal fml = boogieVar as Formal; - if (fml != null && Formals.TryGetValue(fml, out res)) - return (!)res; - - // global variables, local variables, incarnations, etc. are - // bound the first time they occur - if (!UnboundVariables.TryGetValue(boogieVar, out res)) { - res = new VCExprVar (boogieVar.Name, boogieVar.TypedIdent.Type); - UnboundVariables.Bind(boogieVar, res); - } - return (!)res; - } - - /////////////////////////////////////////////////////////////////////////////////// - - internal readonly VCGenerationOptions! GenerationOptions; - - /////////////////////////////////////////////////////////////////////////////////// - - public override LiteralExpr! VisitLiteralExpr(LiteralExpr! node) { - Push(TranslateLiteralExpr(node)); - return node; - } - private VCExpr! TranslateLiteralExpr(LiteralExpr! node) { - if ( node.Val is bool ) - { - bool b = (bool) node.Val; - if ( b ) { - return VCExpressionGenerator.True; - } else { - return VCExpressionGenerator.False; - } - } - else if ( node.Val is BigNum ) - { - return Gen.Integer(node.asBigNum); - } - else if ( node.Val is BvConst ) - { - return Gen.Bitvector((BvConst)node.Val); - } - else - { - System.Diagnostics.Debug.Assert(false, "unknown kind of literal " + node.tok.ToString()); - assert false; - } - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override AIVariableExpr! VisitAIVariableExpr(AIVariableExpr! node) - { - assert false; - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override Expr! VisitIdentifierExpr(IdentifierExpr! node) { - assume node.Decl != null; // the expression has to be resolved - Push(LookupVariable(node.Decl)); - return node; - } - - /////////////////////////////////////////////////////////////////////////////////// - - // Because of our scheme for numbering incarnations of variables, the pre-state - // value of a variable x is always just "x". (The first update to it in a method - // causes it to become "x0". So we just remove old expressions with a visitor - // before transforming it into a VCExpr. - public override Expr! VisitOldExpr(OldExpr! node) - { - assert false; - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override Expr! VisitNAryExpr(NAryExpr! node) - { - Push(TranslateNAryExpr(node)); - return node; - } - - private VCExpr! TranslateNAryExpr(NAryExpr! node) { - int n = node.Args.Length; - List! vcs = new List (n); - for(int i = 0; i < n; i++) - { - vcs.Add(Translate((!)node.Args[i])); - } - - if (node.Type == null) { - System.Console.WriteLine("*** type is null for {0}", node); - assert false; - } - - return IAppTranslator.Translate(node.Fun, node.Type, vcs, - ToList((!)node.TypeParameters)); - } - - - private static List! EMPTY_TYPE_LIST = new List (); - - private List! ToList(TypeParamInstantiation! insts) { - if (insts.FormalTypeParams.Count == 0) - return EMPTY_TYPE_LIST; - - List! typeArgs = new List (); - foreach (TypeVariable! var in insts.FormalTypeParams) - typeArgs.Add(insts[var]); - return typeArgs; - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override QuantifierExpr! VisitQuantifierExpr(QuantifierExpr! node) { - Push(TranslateQuantifierExpr(node)); - return node; - } - - public override ExistsExpr! VisitExistsExpr(ExistsExpr! node) - { - node = (ExistsExpr) this.VisitQuantifierExpr(node); - return node; - } - - public override ForallExpr! VisitForallExpr(ForallExpr! node) - { - node = (ForallExpr) this.VisitQuantifierExpr(node); - return node; - } - - private VCExpr! TranslateQuantifierExpr(QuantifierExpr! node) - { - List! typeParams = new List (); - foreach (TypeVariable! v in node.TypeParameters) - typeParams.Add(v); - - PushBoundVariableScope(); - - List! boundVars = new List (); - foreach (Variable! v in node.Dummies) - boundVars.Add(BindVariable(v)); - - try { - List! triggers = TranslateTriggers(node.Triggers); - VCExpr! body = Translate(node.Body); - VCQuantifierInfos! infos = GenerateQuantifierInfos(node); - - Quantifier quan; - if (node is ForallExpr) - quan = Quantifier.ALL; - else if (node is ExistsExpr) - quan = Quantifier.EX; - else - assert false; - - return Gen.Quantify(quan, typeParams, boundVars, triggers, infos, body); - } finally { - PopBoundVariableScope(); - } - } - - private List! TranslateTriggers(Trigger node) - { - List! res = new List (); - Trigger curTrigger = node; - while (curTrigger != null) { - res.Add(Gen.Trigger(curTrigger.Pos, Translate(curTrigger.Tr))); - curTrigger = curTrigger.Next; - } - return res; - } - - private VCQuantifierInfos! GenerateQuantifierInfos(QuantifierExpr! node) { - string qid = getQidNameFromQKeyValue(node.Dummies, node.Attributes); - return new VCQuantifierInfos(qid, node.SkolemId, false, node.Attributes); - } - - private string getQidNameFromQKeyValue(VariableSeq! vars, QKeyValue attributes) { - // Check for a 'qid, name' pair in keyvalues - string qid = QKeyValue.FindStringAttribute(attributes, "qid"); - if (qid == null && vars.Length != 0){ - // generate default name (line:column position in .bpl file) - Variable v = vars[0]; - assert v != null; // Rustan's claim! - // Include the first 8 characters of the filename in QID (helpful in case we use /concat) - // We limit it to 8, so the SX file doesn't grow too big, and who on earth would need - // more than 8 characters in a filename anyways. - int max = 8; - StringBuilder buf = new StringBuilder(max + 20); - string filename = v.tok.filename; - if (filename == null) filename = "unknown"; - for (int i = 0; i < filename.Length; ++i) { - if (filename[i] == '/' || filename[i] == '\\') buf.Length = 0; - if (buf.Length < max && char.IsLetterOrDigit(filename[i])) { - if (buf.Length == 0 && char.IsDigit(filename[i])) { - // Z3 does not like QID's to start with a digit, so we prepend another character - buf.Append('_'); - } - buf.Append(filename[i]); - } - } - buf.Append('.').Append(v.Line).Append(':').Append(v.Col); - qid = buf.ToString(); - } - return qid; - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override BvExtractExpr! VisitBvExtractExpr(BvExtractExpr! node) - { - Push(TranslateBvExtractExpr(node)); - return node; - } - - private VCExpr! TranslateBvExtractExpr(BvExtractExpr! node) - requires node.Start <= node.End; { - VCExpr! bv = Translate(node.Bitvector); - return Gen.BvExtract(bv, ((!)node.Bitvector.Type).BvBits, node.Start, node.End); - } - - /////////////////////////////////////////////////////////////////////////////////// - - public override BvConcatExpr! VisitBvConcatExpr(BvConcatExpr! node) - { - Push(TranslateBvConcatExpr(node)); - return node; - } - - private VCExpr! TranslateBvConcatExpr(BvConcatExpr! node) { - VCExpr! bv0 = Translate(node.E0); - VCExpr! bv1 = Translate(node.E1); - return Gen.BvConcat(bv0, bv1); - } - - /////////////////////////////////////////////////////////////////////////////////// - // all the other cases should never happen - - public override Cmd! VisitAssertCmd(AssertCmd! node) - { - assert false; - } - public override Cmd! VisitAssignCmd(AssignCmd! node) - { - assert false; - } - public override Cmd! VisitAssumeCmd(AssumeCmd! node) - { - assert false; - } - public override AtomicRE! VisitAtomicRE(AtomicRE! node) - { - assert false; - } - public override Axiom! VisitAxiom(Axiom! node) - { - assert false; - } - public override Type! VisitBasicType(BasicType! node) - { - assert false; - } - public override Type! VisitBvType(BvType! node) - { - assert false; - } - public override Block! VisitBlock(Block! node) - { - assert false; - } - CodeExprConverter codeExprConverter = null; - public void SetCodeExprConverter(CodeExprConverter f){ - this.codeExprConverter = f; - } - public override Expr! VisitCodeExpr(CodeExpr! codeExpr) - { - assume codeExprConverter != null; - - Hashtable/**/ blockVariables = new Hashtable/**/(); - List bindings = new List(); - VCExpr e = codeExprConverter(codeExpr, blockVariables, bindings); - Push(e); - return codeExpr; - } - public override BlockSeq! VisitBlockSeq(BlockSeq! blockSeq) - { - assert false; - } - public override List! VisitBlockList(List! blocks) - { - assert false; - } - public override BoundVariable! VisitBoundVariable(BoundVariable! node) - { - assert false; - } - public override Cmd! VisitCallCmd(CallCmd! node) - { - assert false; - } - public override Cmd! VisitCallForallCmd(CallForallCmd! node) - { - assert false; - } - public override CmdSeq! VisitCmdSeq(CmdSeq! cmdSeq) - { - assert false; - } - public override Choice! VisitChoice(Choice! node) - { - assert false; - } - public override Cmd! VisitCommentCmd(CommentCmd! node) - { - assert false; - } - public override Constant! VisitConstant(Constant! node) - { - assert false; - } - public override CtorType! VisitCtorType(CtorType! node) - { - assert false; - } - public override Declaration! VisitDeclaration(Declaration! node) - { - assert false; - } - public override List! VisitDeclarationList(List! declarationList) - { - assert false; - } - public override DeclWithFormals! VisitDeclWithFormals(DeclWithFormals! node) - { - assert false; - } - public override Requires! VisitRequires(Requires! @requires) - { - assert false; - } - public override RequiresSeq! VisitRequiresSeq(RequiresSeq! requiresSeq) - { - assert false; - } - public override Ensures! VisitEnsures(Ensures! @ensures) - { - assert false; - } - public override EnsuresSeq! VisitEnsuresSeq(EnsuresSeq! ensuresSeq) - { - assert false; - } - public override Formal! VisitFormal(Formal! node) - { - assert false; - } - public override Function! VisitFunction(Function! node) - { - assert false; - } - public override GlobalVariable! VisitGlobalVariable(GlobalVariable! node) - { - assert false; - } - public override GotoCmd! VisitGotoCmd(GotoCmd! node) - { - assert false; - } - public override Cmd! VisitHavocCmd(HavocCmd! node) - { - assert false; - } - public override Implementation! VisitImplementation(Implementation! node) - { - assert false; - } - public override LocalVariable! VisitLocalVariable(LocalVariable! node) - { - assert false; - } - public override AssignLhs! VisitMapAssignLhs(MapAssignLhs! node) - { - assert false; - } - public override MapType! VisitMapType(MapType! node) - { - assert false; - } - public override Procedure! VisitProcedure(Procedure! node) - { - assert false; - } - public override Program! VisitProgram(Program! node) - { - assert false; - } - public override Cmd! VisitRE(RE! node) - { - assert false; - } - public override RESeq! VisitRESeq(RESeq! reSeq) - { - assert false; - } - public override ReturnCmd! VisitReturnCmd(ReturnCmd! node) - { - assert false; - } - public override ReturnExprCmd! VisitReturnExprCmd(ReturnExprCmd! node) - { - assert false; - } - public override Sequential! VisitSequential(Sequential! node) - { - assert false; - } - public override AssignLhs! VisitSimpleAssignLhs(SimpleAssignLhs! node) - { - assert false; - } - public override Cmd! VisitStateCmd(StateCmd! node) - { - assert false; - } - public override TransferCmd! VisitTransferCmd(TransferCmd! node) - { - assert false; - } - public override Trigger! VisitTrigger(Trigger! node) - { - assert false; - } - public override Type! VisitType(Type! node) - { - assert false; - } - public override TypedIdent! VisitTypedIdent(TypedIdent! node) - { - assert false; - } - public override Type! VisitTypeSynonymAnnotation(TypeSynonymAnnotation! node) - { - assert false; - } - public override Type! VisitTypeVariable(TypeVariable! node) - { - assert false; - } - public override Variable! VisitVariable(Variable! node) - { - assert false; - } - public override VariableSeq! VisitVariableSeq(VariableSeq! variableSeq) - { - assert false; - } - public override Cmd! VisitAssertEnsuresCmd(AssertEnsuresCmd! node) - { - assert false; - } - public override Cmd! VisitAssertRequiresCmd(AssertRequiresCmd! node) - { - assert false; - } - - } - - - ///////////////////////////////////////////////////////////////////////////////// - - public class IAppliableTranslator : IAppliableVisitor { - - private readonly Boogie2VCExprTranslator! BaseTranslator; - - private VCExpressionGenerator! Gen { get { - return BaseTranslator.Gen; - } } - private VCGenerationOptions! GenerationOptions { get { - return BaseTranslator.GenerationOptions; - } } - - public IAppliableTranslator(Boogie2VCExprTranslator! baseTranslator) { - this.BaseTranslator = baseTranslator; - } - - /////////////////////////////////////////////////////////////////////////////// - - private List! args = new List(); - private List! typeArgs = new List(); - - public VCExpr! Translate(IAppliable! app, Type! ty, List! args, List! typeArgs) { - - List! oldArgs = this.args; - List! oldTypeArgs = this.typeArgs; - this.args = args; - this.typeArgs = typeArgs; - VCExpr! result = app.Dispatch(this); - this.args = oldArgs; - this.typeArgs = oldTypeArgs; - return result; - } - - /////////////////////////////////////////////////////////////////////////////// - - - - public VCExpr! Visit(UnaryOperator! unaryOperator) { - assert unaryOperator.Op == UnaryOperator.Opcode.Not && this.args.Count == 1; - return Gen.Not(this.args); - } - - public VCExpr! Visit(BinaryOperator! binaryOperator) { - return TranslateBinaryOperator(binaryOperator, this.args); - } - - public VCExpr! Visit(FunctionCall! functionCall) { - return TranslateFunctionCall(functionCall, this.args, this.typeArgs); - } - - public VCExpr! Visit(MapSelect! mapSelect) { - return Gen.Select(this.args, this.typeArgs); - } - - public VCExpr! Visit(MapStore! mapStore) { - return Gen.Store(this.args, this.typeArgs); - } - - public VCExpr! Visit(TypeCoercion! typeCoercion) { - assert this.args.Count == 1; - return this.args[0]; - } - - public VCExpr! Visit(IfThenElse! ite) { - return Gen.Function(VCExpressionGenerator.IfThenElseOp, this.args); - } - - /////////////////////////////////////////////////////////////////////////////// - - private VCExpr! TranslateBinaryOperator(BinaryOperator! app, List! args) { - assert args.Count == 2; - - switch (app.Op) { - case BinaryOperator.Opcode.Add: - return Gen.Function(VCExpressionGenerator.AddOp, args); - case BinaryOperator.Opcode.Sub: - return Gen.Function(VCExpressionGenerator.SubOp, args); - case BinaryOperator.Opcode.Mul: - return Gen.Function(VCExpressionGenerator.MulOp, args); - case BinaryOperator.Opcode.Div: - return Gen.Function(VCExpressionGenerator.DivOp, args); - case BinaryOperator.Opcode.Mod: - return Gen.Function(VCExpressionGenerator.ModOp, args); - case BinaryOperator.Opcode.Eq: - case BinaryOperator.Opcode.Iff: - // we don't distinguish between equality and equivalence at this point - return Gen.Function(VCExpressionGenerator.EqOp, args); - case BinaryOperator.Opcode.Neq: - return Gen.Function(VCExpressionGenerator.NeqOp, args); - case BinaryOperator.Opcode.Lt: - return Gen.Function(VCExpressionGenerator.LtOp, args); - case BinaryOperator.Opcode.Le: - return Gen.Function(VCExpressionGenerator.LeOp, args); - case BinaryOperator.Opcode.Ge: - return Gen.Function(VCExpressionGenerator.GeOp, args); - case BinaryOperator.Opcode.Gt: - return Gen.Function(VCExpressionGenerator.GtOp, args); - case BinaryOperator.Opcode.Imp: - return Gen.Function(VCExpressionGenerator.ImpliesOp, args); - case BinaryOperator.Opcode.And: - return Gen.Function(VCExpressionGenerator.AndOp, args); - case BinaryOperator.Opcode.Or: - return Gen.Function(VCExpressionGenerator.OrOp, args); - case BinaryOperator.Opcode.Subtype: - return Gen.Function(VCExpressionGenerator.SubtypeOp, args); - default: - assert false; // unexpected binary operator - } - } - - /////////////////////////////////////////////////////////////////////////////// - - private VCExpr! TranslateFunctionCall(FunctionCall! app, - List! args, List! typeArgs) { - assert app.Func != null; // resolution must have happened - - VCExpr res = ApplyExpansion(app, args, typeArgs); - if (res != null) - return res; - - VCExprOp! functionOp = Gen.BoogieFunctionOp(app.Func); - return Gen.Function(functionOp, args, typeArgs); - } - - private VCExpr ApplyExpansion(FunctionCall! app, - List! args, List! typeArgs) { - assert app.Func != null; // resolution must have happened - - if (app.Func.doingExpansion) { - System.Console.WriteLine("*** detected expansion loop on {0}", app.Func); - return null; - } - - Expansion exp = FindExpansion(app.Func); - if (exp == null) - return null; - - VCExpr! translatedBody; - VCExprSubstitution! subst = new VCExprSubstitution(); - try { - BaseTranslator.PushFormalsScope(); - BaseTranslator.PushBoundVariableScope(); - app.Func.doingExpansion = true; - - // first bind the formals to VCExpr variables, which are later - // substituted with the actual parameters - for (int i = 0; i < exp.formals.Length; ++i) - subst[BaseTranslator.BindVariable((!)exp.formals[i])] = args[i]; - - // recursively translate the body of the expansion - translatedBody = BaseTranslator.Translate(exp.body); - } finally { - BaseTranslator.PopFormalsScope(); - BaseTranslator.PopBoundVariableScope(); - app.Func.doingExpansion = false; - } - - // substitute the formals with the actual parameters in the body - assert typeArgs.Count == exp.TypeParameters.Length; - for (int i = 0; i < typeArgs.Count; ++i) - subst[exp.TypeParameters[i]] = typeArgs[i]; - SubstitutingVCExprVisitor! substituter = new SubstitutingVCExprVisitor (Gen); - return substituter.Mutate(translatedBody, subst); - } - - private Expansion? FindExpansion(Function! func) - { - if (func.expansions == null) return null; - - Expansion? exp = null; - foreach (Expansion! e in func.expansions) { - if (e.ignore == null || !GenerationOptions.IsAnyProverCommandSupported(e.ignore)) { - if (exp == null) { - exp = e; - } else { - System.Console.WriteLine("*** more than one possible expansion for {0}", func); - return null; - } - } - } - - return exp; - } - } -} diff --git a/Source/VCExpr/Clustering.cs b/Source/VCExpr/Clustering.cs new file mode 100644 index 00000000..3b256121 --- /dev/null +++ b/Source/VCExpr/Clustering.cs @@ -0,0 +1,449 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// Code for managing and clusterings sets of terms; this is used to +// compress the input given to the theorem prover + +namespace Microsoft.Boogie.Clustering +{ + using Microsoft.Boogie.VCExprAST; + + + public class SubtermCollector : BoundVarTraversingVCExprVisitor { + + private readonly VCExpressionGenerator! Gen; + + public SubtermCollector(VCExpressionGenerator! gen) { + Gen = gen; + } + + // variables that are global and treated like constants + private readonly IDictionary! GlobalVariables = + new Dictionary (); + + private readonly IDictionary! SubtermClusters = + new Dictionary (); + + public void UnifyClusters() { + foreach (KeyValuePair pair + in SubtermClusters) + pair.Value.UnifyClusters(); + } + + //////////////////////////////////////////////////////////////////////////// + + protected override bool StandardResult(VCExpr! node, bool arg) { + return false; // by default, do not collect terms containing node + } + + public override bool Visit(VCExprLiteral! node, bool arg) { + return true; + } + + public override bool Visit(VCExprNAry! node, bool arg) { + VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp; + if (op == null) { + base.Visit(node, arg); + return false; + } + + bool res = true; + foreach (VCExpr! subexpr in node) + res &= this.Traverse(subexpr, arg); + + if (res) { + TermClustersSameHead clusters; + if (!SubtermClusters.TryGetValue(op, out clusters)) { + clusters = new TermClustersSameHead(op, GlobalVariables, Gen); + SubtermClusters.Add(op, clusters); + } + ((!)clusters).AddExpr(node); + } + + return res; + } + + public override bool Visit(VCExprVar! node, bool arg) { + if (!BoundTermVars.Contains(node)) + GlobalVariables[node] = node; + return true; + } + + [Pure] + public override string! ToString() + { + string! res = ""; + foreach (KeyValuePair pair + in SubtermClusters) + res = res + pair.Value + "\n"; + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + // Class for managing and clustering a set of terms that all start + // with the same function symbol + internal class TermClustersSameHead { + + public readonly VCExprOp! Op; + private readonly VCExpressionGenerator! Gen; + + public TermClustersSameHead(VCExprOp! op, + IDictionary! globalVars, + VCExpressionGenerator! gen) { + Op = op; + GlobalVariables = globalVars; + Gen = gen; + } + + // variables that are global and treated like constants + private readonly IDictionary! GlobalVariables; + + private readonly List! Clusters = new List (); + + private struct Cluster { + public readonly VCExprNAry! Generator; + public readonly int Size; + + public Cluster(VCExprNAry! generator, int size) { + Generator = generator; + Size = size; + } + } + + private int Distance(Cluster a, Cluster b) { + AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); + visitor.AntiUnify(a.Generator, b.Generator); + + int reprSizeA, reprSizeB; + visitor.RepresentationSize(GlobalVariables, out reprSizeA, out reprSizeB); + return (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; + } + + private bool EqualUpToRenaming(Cluster a, Cluster b) { + AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); + visitor.AntiUnify(a.Generator, b.Generator); + return visitor.RepresentationIsRenaming(GlobalVariables); + } + + private Cluster Merge(Cluster a, Cluster b) { + AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); + VCExpr! generator = visitor.AntiUnify(a.Generator, b.Generator); + VCExprNAry generatorNAry = generator as VCExprNAry; + assert generatorNAry != null && Op.Equals(generatorNAry.Op); + return new Cluster(generatorNAry, a.Size + b.Size); + } + + //////////////////////////////////////////////////////////////////////////// + + public void AddExpr(VCExprNAry! expr) + requires Op.Equals(expr.Op); { + + Cluster c = new Cluster (expr, 1); + for (int i = 0; i < Clusters.Count; ++i) { + Cluster d = Clusters[i]; + if (EqualUpToRenaming(c, d)) { + Clusters[i] = new Cluster (d.Generator, d.Size + 1); + return; + } + } + + Clusters.Add(c); + } + + //////////////////////////////////////////////////////////////////////////// + + private struct ClusteringMatrix { + + private readonly VCExpressionGenerator! Gen; + private readonly IDictionary! GlobalVariables; + + public readonly List! Clusters; + public readonly bool[]! RemainingClusters; + + public readonly Distance[,]! Distances; + + public struct Distance { + public readonly int Dist; + public readonly VCExprNAry! Generator; + + public Distance(Cluster a, Cluster b, + IDictionary! globalVars, + VCExpressionGenerator! gen) { + AntiUnificationVisitor! visitor = new AntiUnificationVisitor (gen); + Generator = (VCExprNAry)visitor.AntiUnify(a.Generator, b.Generator); + + int reprSizeA, reprSizeB; + visitor.RepresentationSize(globalVars, out reprSizeA, out reprSizeB); + Dist = (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; + } + } + + public ClusteringMatrix(List! clusters, + IDictionary! globalVars, + VCExpressionGenerator! gen) { + List! c = new List (); + c.AddRange(clusters); + Clusters = c; + + GlobalVariables = globalVars; + Gen = gen; + + bool[] remaining = new bool [clusters.Count]; + RemainingClusters = remaining; + for (int i = 0; i < remaining.Length; ++i) + remaining[i] = true; + + Distance[,]! distances = new Distance [clusters.Count, clusters.Count]; + Distances = distances; + for (int i = 1; i < clusters.Count; ++i) + for (int j = 0; j < i; ++j) + distances[i, j] = + new Distance (clusters[i], clusters[j], GlobalVariables, Gen); + } + + public void UnifyClusters(int maxDist) { + while (true) { + int i, j; + int minDist = FindMinDistance(out i, out j); + + if (minDist > maxDist) + return; + + MergeClusters(i, j); + } + } + + public void ResultingClusters(List! clusters) { + clusters.Clear(); + for (int i = 0; i < Clusters.Count; ++i) + if (RemainingClusters[i]) + clusters.Add(Clusters[i]); + } + + ////////////////////////////////////////////////////////////////////////// + + private void Update(int i) { + for (int j = 0; j < i; ++j) { + if (RemainingClusters[j]) + Distances[i, j] = + new Distance (Clusters[i], Clusters[j], GlobalVariables, Gen); + } + for (int j = i + 1; j < Clusters.Count; ++j) { + if (RemainingClusters[j]) + Distances[j, i] = + new Distance (Clusters[j], Clusters[i], GlobalVariables, Gen); + } + } + + private int FindMinDistance(out int c0, out int c1) { + int minDist = int.MaxValue; + c0 = -1; + c1 = -1; + + for (int i = 0; i < Clusters.Count; ++i) + if (RemainingClusters[i]) { + for (int j = 0; j < i; ++j) + if (RemainingClusters[j]) { + if (Distances[i, j].Dist < minDist) { + minDist = Distances[i, j].Dist; + c0 = i; + c1 = j; + } + } + } + + assert c0 == -1 && c1 == -1 || c0 > c1 && c1 >= 0; + return minDist; + } + + private void MergeClusters(int i, int j) + requires j >= 0 && i > j && + RemainingClusters[i] && RemainingClusters[j]; { + Clusters[i] = new Cluster (Distances[i, j].Generator, + Clusters[i].Size + Clusters[j].Size); + RemainingClusters[j] = false; + Update(i); + } + } + + //////////////////////////////////////////////////////////////////////////// + + public void UnifyClusters() { + ClusteringMatrix matrix = + new ClusteringMatrix (Clusters, GlobalVariables, Gen); + matrix.UnifyClusters(50); + matrix.ResultingClusters(Clusters); + } + + [Pure] + public override string! ToString() + { + string! res = ""; + foreach (Cluster c in Clusters) + res = res + c.Generator + "\t" + c.Size + "\n"; + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + internal class AntiUnificationVisitor : TraversingVCExprVisitor { + + private readonly VCExpressionGenerator! Gen; + + public AntiUnificationVisitor(VCExpressionGenerator! gen) { + Gen = gen; + } + + // Sub-expressions in the first and second expression to be + // anti-unified that are replaced with variables + private readonly IDictionary! Representation = + new Dictionary (); + + private struct ExprPair { + public readonly VCExpr! Expr0, Expr1; + public ExprPair(VCExpr! expr0, VCExpr! expr1) { + Expr0 = expr0; + Expr1 = expr1; + } + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (that is ExprPair) { + ExprPair thatPair = (ExprPair)that; + return this.Expr0.Equals(thatPair.Expr0) && + this.Expr1.Equals(thatPair.Expr1); + } + return false; + } + [Pure] + public override int GetHashCode() { + return Expr0.GetHashCode() + Expr1.GetHashCode() * 13; + } + } + + public void Reset() { + Representation.Clear (); + } + + public bool RepresentationIsRenaming(IDictionary! globalVars) { + if (!forall{KeyValuePair pair in Representation; + pair.Key.Expr0 is VCExprVar && + pair.Key.Expr1 is VCExprVar && + !globalVars.ContainsKey((VCExprVar!)pair.Key.Expr0) && + !globalVars.ContainsKey((VCExprVar!)pair.Key.Expr1)}) + return false; + // check that all substituted variables are distinct + // TODO: optimise + return + forall{KeyValuePair pair1 in Representation; + forall{KeyValuePair pair2 in Representation; + pair1.Value.Equals(pair2.Value) || !pair1.Key.Expr0.Equals(pair2.Key.Expr0) + && !pair1.Key.Expr1.Equals(pair2.Key.Expr1) + }}; + } + + public void RepresentationSize(IDictionary! globalVars, + out int expr0Size, out int expr1Size) { + ReprSizeComputingVisitor! size0Visitor = new ReprSizeComputingVisitor (); + ReprSizeComputingVisitor! size1Visitor = new ReprSizeComputingVisitor (); + + foreach (KeyValuePair pair in Representation) { + size0Visitor.ComputeSize(pair.Key.Expr0, globalVars); + size1Visitor.ComputeSize(pair.Key.Expr1, globalVars); + } + + expr0Size = size0Visitor.Size; + expr1Size = size1Visitor.Size; + } + + public VCExpr! AntiUnify(VCExpr! s, VCExpr! t) + requires s.Type.Equals(t.Type); { + return Traverse(s, t); + } + + //////////////////////////////////////////////////////////////////////////// + + private VCExprVar! AbstractWithVariable(VCExpr! s, VCExpr! t) + requires s.Type.Equals(t.Type); { + + ExprPair pair = new ExprPair (s, t); + VCExprVar repr; + if (!Representation.TryGetValue(pair, out repr)) { + repr = Gen.Variable("abs" + Representation.Count, s.Type); + Representation.Add(pair, repr); + } + return (!)repr; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprLiteral! node, VCExpr! that) { + if (node.Equals(that)) + return node; + return AbstractWithVariable(node, that); + } + + public override VCExpr! Visit(VCExprNAry! node, VCExpr! that) { + VCExprNAry thatNAry = that as VCExprNAry; + if (thatNAry != null && node.Op.Equals(thatNAry.Op)) { + // type parameters should already have been eliminated at this + // stage + assert node.TypeParamArity == 0 && thatNAry.TypeParamArity == 0 && + node.Arity == thatNAry.Arity; + + List! unifiedArgs = new List (); + for (int i = 0; i < node.Arity; ++i) + unifiedArgs.Add(Traverse(node[i], thatNAry[i])); + + return Gen.Function(node.Op, unifiedArgs); + } + return AbstractWithVariable(node, that); + } + + public override VCExpr! Visit(VCExprVar! node, VCExpr! that) { + if (node.Equals(that)) + return node; + return AbstractWithVariable(node, that); + } + + protected override VCExpr! StandardResult(VCExpr! node, VCExpr! that) { + assert false; // not handled here + } + } + + ////////////////////////////////////////////////////////////////////////////// + + internal class ReprSizeComputingVisitor + : TraversingVCExprVisitor!> { + + public int Size = 0; + + public void ComputeSize(VCExpr! expr, + IDictionary! globalVars) { + Traverse(expr, globalVars); + } + + protected override bool StandardResult(VCExpr! node, + IDictionary! globalVars) { + VCExprVar nodeAsVar = node as VCExprVar; + if (nodeAsVar == null || globalVars.ContainsKey(nodeAsVar)) + Size = Size + 1; + return true; + } + } +} \ No newline at end of file diff --git a/Source/VCExpr/Clustering.ssc b/Source/VCExpr/Clustering.ssc deleted file mode 100644 index 3b256121..00000000 --- a/Source/VCExpr/Clustering.ssc +++ /dev/null @@ -1,449 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// Code for managing and clusterings sets of terms; this is used to -// compress the input given to the theorem prover - -namespace Microsoft.Boogie.Clustering -{ - using Microsoft.Boogie.VCExprAST; - - - public class SubtermCollector : BoundVarTraversingVCExprVisitor { - - private readonly VCExpressionGenerator! Gen; - - public SubtermCollector(VCExpressionGenerator! gen) { - Gen = gen; - } - - // variables that are global and treated like constants - private readonly IDictionary! GlobalVariables = - new Dictionary (); - - private readonly IDictionary! SubtermClusters = - new Dictionary (); - - public void UnifyClusters() { - foreach (KeyValuePair pair - in SubtermClusters) - pair.Value.UnifyClusters(); - } - - //////////////////////////////////////////////////////////////////////////// - - protected override bool StandardResult(VCExpr! node, bool arg) { - return false; // by default, do not collect terms containing node - } - - public override bool Visit(VCExprLiteral! node, bool arg) { - return true; - } - - public override bool Visit(VCExprNAry! node, bool arg) { - VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp; - if (op == null) { - base.Visit(node, arg); - return false; - } - - bool res = true; - foreach (VCExpr! subexpr in node) - res &= this.Traverse(subexpr, arg); - - if (res) { - TermClustersSameHead clusters; - if (!SubtermClusters.TryGetValue(op, out clusters)) { - clusters = new TermClustersSameHead(op, GlobalVariables, Gen); - SubtermClusters.Add(op, clusters); - } - ((!)clusters).AddExpr(node); - } - - return res; - } - - public override bool Visit(VCExprVar! node, bool arg) { - if (!BoundTermVars.Contains(node)) - GlobalVariables[node] = node; - return true; - } - - [Pure] - public override string! ToString() - { - string! res = ""; - foreach (KeyValuePair pair - in SubtermClusters) - res = res + pair.Value + "\n"; - return res; - } - } - - ////////////////////////////////////////////////////////////////////////////// - - // Class for managing and clustering a set of terms that all start - // with the same function symbol - internal class TermClustersSameHead { - - public readonly VCExprOp! Op; - private readonly VCExpressionGenerator! Gen; - - public TermClustersSameHead(VCExprOp! op, - IDictionary! globalVars, - VCExpressionGenerator! gen) { - Op = op; - GlobalVariables = globalVars; - Gen = gen; - } - - // variables that are global and treated like constants - private readonly IDictionary! GlobalVariables; - - private readonly List! Clusters = new List (); - - private struct Cluster { - public readonly VCExprNAry! Generator; - public readonly int Size; - - public Cluster(VCExprNAry! generator, int size) { - Generator = generator; - Size = size; - } - } - - private int Distance(Cluster a, Cluster b) { - AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); - visitor.AntiUnify(a.Generator, b.Generator); - - int reprSizeA, reprSizeB; - visitor.RepresentationSize(GlobalVariables, out reprSizeA, out reprSizeB); - return (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; - } - - private bool EqualUpToRenaming(Cluster a, Cluster b) { - AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); - visitor.AntiUnify(a.Generator, b.Generator); - return visitor.RepresentationIsRenaming(GlobalVariables); - } - - private Cluster Merge(Cluster a, Cluster b) { - AntiUnificationVisitor! visitor = new AntiUnificationVisitor (Gen); - VCExpr! generator = visitor.AntiUnify(a.Generator, b.Generator); - VCExprNAry generatorNAry = generator as VCExprNAry; - assert generatorNAry != null && Op.Equals(generatorNAry.Op); - return new Cluster(generatorNAry, a.Size + b.Size); - } - - //////////////////////////////////////////////////////////////////////////// - - public void AddExpr(VCExprNAry! expr) - requires Op.Equals(expr.Op); { - - Cluster c = new Cluster (expr, 1); - for (int i = 0; i < Clusters.Count; ++i) { - Cluster d = Clusters[i]; - if (EqualUpToRenaming(c, d)) { - Clusters[i] = new Cluster (d.Generator, d.Size + 1); - return; - } - } - - Clusters.Add(c); - } - - //////////////////////////////////////////////////////////////////////////// - - private struct ClusteringMatrix { - - private readonly VCExpressionGenerator! Gen; - private readonly IDictionary! GlobalVariables; - - public readonly List! Clusters; - public readonly bool[]! RemainingClusters; - - public readonly Distance[,]! Distances; - - public struct Distance { - public readonly int Dist; - public readonly VCExprNAry! Generator; - - public Distance(Cluster a, Cluster b, - IDictionary! globalVars, - VCExpressionGenerator! gen) { - AntiUnificationVisitor! visitor = new AntiUnificationVisitor (gen); - Generator = (VCExprNAry)visitor.AntiUnify(a.Generator, b.Generator); - - int reprSizeA, reprSizeB; - visitor.RepresentationSize(globalVars, out reprSizeA, out reprSizeB); - Dist = (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; - } - } - - public ClusteringMatrix(List! clusters, - IDictionary! globalVars, - VCExpressionGenerator! gen) { - List! c = new List (); - c.AddRange(clusters); - Clusters = c; - - GlobalVariables = globalVars; - Gen = gen; - - bool[] remaining = new bool [clusters.Count]; - RemainingClusters = remaining; - for (int i = 0; i < remaining.Length; ++i) - remaining[i] = true; - - Distance[,]! distances = new Distance [clusters.Count, clusters.Count]; - Distances = distances; - for (int i = 1; i < clusters.Count; ++i) - for (int j = 0; j < i; ++j) - distances[i, j] = - new Distance (clusters[i], clusters[j], GlobalVariables, Gen); - } - - public void UnifyClusters(int maxDist) { - while (true) { - int i, j; - int minDist = FindMinDistance(out i, out j); - - if (minDist > maxDist) - return; - - MergeClusters(i, j); - } - } - - public void ResultingClusters(List! clusters) { - clusters.Clear(); - for (int i = 0; i < Clusters.Count; ++i) - if (RemainingClusters[i]) - clusters.Add(Clusters[i]); - } - - ////////////////////////////////////////////////////////////////////////// - - private void Update(int i) { - for (int j = 0; j < i; ++j) { - if (RemainingClusters[j]) - Distances[i, j] = - new Distance (Clusters[i], Clusters[j], GlobalVariables, Gen); - } - for (int j = i + 1; j < Clusters.Count; ++j) { - if (RemainingClusters[j]) - Distances[j, i] = - new Distance (Clusters[j], Clusters[i], GlobalVariables, Gen); - } - } - - private int FindMinDistance(out int c0, out int c1) { - int minDist = int.MaxValue; - c0 = -1; - c1 = -1; - - for (int i = 0; i < Clusters.Count; ++i) - if (RemainingClusters[i]) { - for (int j = 0; j < i; ++j) - if (RemainingClusters[j]) { - if (Distances[i, j].Dist < minDist) { - minDist = Distances[i, j].Dist; - c0 = i; - c1 = j; - } - } - } - - assert c0 == -1 && c1 == -1 || c0 > c1 && c1 >= 0; - return minDist; - } - - private void MergeClusters(int i, int j) - requires j >= 0 && i > j && - RemainingClusters[i] && RemainingClusters[j]; { - Clusters[i] = new Cluster (Distances[i, j].Generator, - Clusters[i].Size + Clusters[j].Size); - RemainingClusters[j] = false; - Update(i); - } - } - - //////////////////////////////////////////////////////////////////////////// - - public void UnifyClusters() { - ClusteringMatrix matrix = - new ClusteringMatrix (Clusters, GlobalVariables, Gen); - matrix.UnifyClusters(50); - matrix.ResultingClusters(Clusters); - } - - [Pure] - public override string! ToString() - { - string! res = ""; - foreach (Cluster c in Clusters) - res = res + c.Generator + "\t" + c.Size + "\n"; - return res; - } - } - - ////////////////////////////////////////////////////////////////////////////// - - internal class AntiUnificationVisitor : TraversingVCExprVisitor { - - private readonly VCExpressionGenerator! Gen; - - public AntiUnificationVisitor(VCExpressionGenerator! gen) { - Gen = gen; - } - - // Sub-expressions in the first and second expression to be - // anti-unified that are replaced with variables - private readonly IDictionary! Representation = - new Dictionary (); - - private struct ExprPair { - public readonly VCExpr! Expr0, Expr1; - public ExprPair(VCExpr! expr0, VCExpr! expr1) { - Expr0 = expr0; - Expr1 = expr1; - } - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (that is ExprPair) { - ExprPair thatPair = (ExprPair)that; - return this.Expr0.Equals(thatPair.Expr0) && - this.Expr1.Equals(thatPair.Expr1); - } - return false; - } - [Pure] - public override int GetHashCode() { - return Expr0.GetHashCode() + Expr1.GetHashCode() * 13; - } - } - - public void Reset() { - Representation.Clear (); - } - - public bool RepresentationIsRenaming(IDictionary! globalVars) { - if (!forall{KeyValuePair pair in Representation; - pair.Key.Expr0 is VCExprVar && - pair.Key.Expr1 is VCExprVar && - !globalVars.ContainsKey((VCExprVar!)pair.Key.Expr0) && - !globalVars.ContainsKey((VCExprVar!)pair.Key.Expr1)}) - return false; - // check that all substituted variables are distinct - // TODO: optimise - return - forall{KeyValuePair pair1 in Representation; - forall{KeyValuePair pair2 in Representation; - pair1.Value.Equals(pair2.Value) || !pair1.Key.Expr0.Equals(pair2.Key.Expr0) - && !pair1.Key.Expr1.Equals(pair2.Key.Expr1) - }}; - } - - public void RepresentationSize(IDictionary! globalVars, - out int expr0Size, out int expr1Size) { - ReprSizeComputingVisitor! size0Visitor = new ReprSizeComputingVisitor (); - ReprSizeComputingVisitor! size1Visitor = new ReprSizeComputingVisitor (); - - foreach (KeyValuePair pair in Representation) { - size0Visitor.ComputeSize(pair.Key.Expr0, globalVars); - size1Visitor.ComputeSize(pair.Key.Expr1, globalVars); - } - - expr0Size = size0Visitor.Size; - expr1Size = size1Visitor.Size; - } - - public VCExpr! AntiUnify(VCExpr! s, VCExpr! t) - requires s.Type.Equals(t.Type); { - return Traverse(s, t); - } - - //////////////////////////////////////////////////////////////////////////// - - private VCExprVar! AbstractWithVariable(VCExpr! s, VCExpr! t) - requires s.Type.Equals(t.Type); { - - ExprPair pair = new ExprPair (s, t); - VCExprVar repr; - if (!Representation.TryGetValue(pair, out repr)) { - repr = Gen.Variable("abs" + Representation.Count, s.Type); - Representation.Add(pair, repr); - } - return (!)repr; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprLiteral! node, VCExpr! that) { - if (node.Equals(that)) - return node; - return AbstractWithVariable(node, that); - } - - public override VCExpr! Visit(VCExprNAry! node, VCExpr! that) { - VCExprNAry thatNAry = that as VCExprNAry; - if (thatNAry != null && node.Op.Equals(thatNAry.Op)) { - // type parameters should already have been eliminated at this - // stage - assert node.TypeParamArity == 0 && thatNAry.TypeParamArity == 0 && - node.Arity == thatNAry.Arity; - - List! unifiedArgs = new List (); - for (int i = 0; i < node.Arity; ++i) - unifiedArgs.Add(Traverse(node[i], thatNAry[i])); - - return Gen.Function(node.Op, unifiedArgs); - } - return AbstractWithVariable(node, that); - } - - public override VCExpr! Visit(VCExprVar! node, VCExpr! that) { - if (node.Equals(that)) - return node; - return AbstractWithVariable(node, that); - } - - protected override VCExpr! StandardResult(VCExpr! node, VCExpr! that) { - assert false; // not handled here - } - } - - ////////////////////////////////////////////////////////////////////////////// - - internal class ReprSizeComputingVisitor - : TraversingVCExprVisitor!> { - - public int Size = 0; - - public void ComputeSize(VCExpr! expr, - IDictionary! globalVars) { - Traverse(expr, globalVars); - } - - protected override bool StandardResult(VCExpr! node, - IDictionary! globalVars) { - VCExprVar nodeAsVar = node as VCExprVar; - if (nodeAsVar == null || globalVars.ContainsKey(nodeAsVar)) - Size = Size + 1; - return true; - } - } -} \ No newline at end of file diff --git a/Source/VCExpr/LetBindingSorter.cs b/Source/VCExpr/LetBindingSorter.cs new file mode 100644 index 00000000..96eb0af2 --- /dev/null +++ b/Source/VCExpr/LetBindingSorter.cs @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// Sort the bindings in a let-expression so that terms bound earlier do +// not contain variables bound later + +namespace Microsoft.Boogie.VCExprAST +{ + + // (argument is not used) + public class LetBindingSorter : MutatingVCExprVisitor { + + private readonly FreeVariableCollector! FreeVarCollector = + new FreeVariableCollector (); + + private List! FreeVarsIn(VCExpr! expr) { + FreeVarCollector.Collect(expr); + List! freeVars = new List (FreeVarCollector.FreeTermVars.Keys); + FreeVarCollector.Reset(); + return freeVars; + } + + public LetBindingSorter(VCExpressionGenerator! gen) { + base(gen); + } + + public override VCExpr! Visit(VCExprLet! node, bool arg) { + IDictionary boundVars = + new Dictionary (); + + // recurse and collect the free variables in bound terms and formulae + foreach (VCExprLetBinding! binding in node) { + VCExpr! newE = Mutate(binding.E, arg); + Binding! b = new Binding (binding.V, newE, FreeVarsIn(newE)); + boundVars.Add(b.V, b); + } + + // generate the occurrence edges + foreach (KeyValuePair pair in boundVars) { + Binding! b = pair.Value; + foreach (VCExprVar! v in b.FreeVars) { + Binding b2; + if (boundVars.TryGetValue(v, out b2)) { + ((!)b2).Occurrences.Add(b); + b.InvOccurrencesNum = b.InvOccurrencesNum + 1; + } + } + } + + // topological sort + Stack rootBindings = new Stack (); + foreach (KeyValuePair pair in boundVars) + if (pair.Value.InvOccurrencesNum == 0) + rootBindings.Push(pair.Value); + + List! sortedBindings = new List (); + while (rootBindings.Count > 0) { + Binding! b = rootBindings.Pop(); + sortedBindings.Add(b); + foreach (Binding! b2 in b.Occurrences) { + b2.InvOccurrencesNum = b2.InvOccurrencesNum - 1; + if (b2.InvOccurrencesNum == 0) + rootBindings.Push(b2); + } + } + + if (exists{KeyValuePair pair in boundVars; + pair.Value.InvOccurrencesNum > 0}) + System.Diagnostics.Debug.Fail("Cyclic let-bindings"); + + assert node.Length == sortedBindings.Count; + + // check which of the bindings can be dropped + VCExpr! newBody = Mutate(node.Body, arg); + + IDictionary! usedVars = + new Dictionary (); + foreach (VCExprVar! v in FreeVarsIn(newBody)) + if (!usedVars.ContainsKey(v)) + usedVars.Add(v, v); + + for (int i = sortedBindings.Count - 1; i >= 0; --i) { + if (usedVars.ContainsKey(sortedBindings[i].V)) { + foreach (VCExprVar! v in sortedBindings[i].FreeVars) + if (!usedVars.ContainsKey(v)) + usedVars.Add(v, v); + } else { + sortedBindings.RemoveAt(i); + } + } + + // assemble the resulting let-expression + List! newBindings = new List (); + foreach (Binding b in sortedBindings) + newBindings.Add(Gen.LetBinding(b.V, b.E)); + + return Gen.Let(newBindings, newBody); + } + + private class Binding { + public readonly VCExprVar! V; + public readonly VCExpr! E; + public readonly List! FreeVars; + + // list of all bound expression in which the variable V occurs + // (outgoing edges) + public readonly List! Occurrences; + + // number of variables that are bound in this let-expression + // and that occur in FreeVars + // (incoming edges) + public int InvOccurrencesNum; + + public Binding(VCExprVar! v, VCExpr! e, List! freeVars) { + this.V = v; + this.E = e; + this.FreeVars = freeVars; + this.Occurrences = new List (); + this.InvOccurrencesNum = 0; + } + } + + } + +} diff --git a/Source/VCExpr/LetBindingSorter.ssc b/Source/VCExpr/LetBindingSorter.ssc deleted file mode 100644 index 96eb0af2..00000000 --- a/Source/VCExpr/LetBindingSorter.ssc +++ /dev/null @@ -1,135 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// Sort the bindings in a let-expression so that terms bound earlier do -// not contain variables bound later - -namespace Microsoft.Boogie.VCExprAST -{ - - // (argument is not used) - public class LetBindingSorter : MutatingVCExprVisitor { - - private readonly FreeVariableCollector! FreeVarCollector = - new FreeVariableCollector (); - - private List! FreeVarsIn(VCExpr! expr) { - FreeVarCollector.Collect(expr); - List! freeVars = new List (FreeVarCollector.FreeTermVars.Keys); - FreeVarCollector.Reset(); - return freeVars; - } - - public LetBindingSorter(VCExpressionGenerator! gen) { - base(gen); - } - - public override VCExpr! Visit(VCExprLet! node, bool arg) { - IDictionary boundVars = - new Dictionary (); - - // recurse and collect the free variables in bound terms and formulae - foreach (VCExprLetBinding! binding in node) { - VCExpr! newE = Mutate(binding.E, arg); - Binding! b = new Binding (binding.V, newE, FreeVarsIn(newE)); - boundVars.Add(b.V, b); - } - - // generate the occurrence edges - foreach (KeyValuePair pair in boundVars) { - Binding! b = pair.Value; - foreach (VCExprVar! v in b.FreeVars) { - Binding b2; - if (boundVars.TryGetValue(v, out b2)) { - ((!)b2).Occurrences.Add(b); - b.InvOccurrencesNum = b.InvOccurrencesNum + 1; - } - } - } - - // topological sort - Stack rootBindings = new Stack (); - foreach (KeyValuePair pair in boundVars) - if (pair.Value.InvOccurrencesNum == 0) - rootBindings.Push(pair.Value); - - List! sortedBindings = new List (); - while (rootBindings.Count > 0) { - Binding! b = rootBindings.Pop(); - sortedBindings.Add(b); - foreach (Binding! b2 in b.Occurrences) { - b2.InvOccurrencesNum = b2.InvOccurrencesNum - 1; - if (b2.InvOccurrencesNum == 0) - rootBindings.Push(b2); - } - } - - if (exists{KeyValuePair pair in boundVars; - pair.Value.InvOccurrencesNum > 0}) - System.Diagnostics.Debug.Fail("Cyclic let-bindings"); - - assert node.Length == sortedBindings.Count; - - // check which of the bindings can be dropped - VCExpr! newBody = Mutate(node.Body, arg); - - IDictionary! usedVars = - new Dictionary (); - foreach (VCExprVar! v in FreeVarsIn(newBody)) - if (!usedVars.ContainsKey(v)) - usedVars.Add(v, v); - - for (int i = sortedBindings.Count - 1; i >= 0; --i) { - if (usedVars.ContainsKey(sortedBindings[i].V)) { - foreach (VCExprVar! v in sortedBindings[i].FreeVars) - if (!usedVars.ContainsKey(v)) - usedVars.Add(v, v); - } else { - sortedBindings.RemoveAt(i); - } - } - - // assemble the resulting let-expression - List! newBindings = new List (); - foreach (Binding b in sortedBindings) - newBindings.Add(Gen.LetBinding(b.V, b.E)); - - return Gen.Let(newBindings, newBody); - } - - private class Binding { - public readonly VCExprVar! V; - public readonly VCExpr! E; - public readonly List! FreeVars; - - // list of all bound expression in which the variable V occurs - // (outgoing edges) - public readonly List! Occurrences; - - // number of variables that are bound in this let-expression - // and that occur in FreeVars - // (incoming edges) - public int InvOccurrencesNum; - - public Binding(VCExprVar! v, VCExpr! e, List! freeVars) { - this.V = v; - this.E = e; - this.FreeVars = freeVars; - this.Occurrences = new List (); - this.InvOccurrencesNum = 0; - } - } - - } - -} diff --git a/Source/VCExpr/NameClashResolver.cs b/Source/VCExpr/NameClashResolver.cs new file mode 100644 index 00000000..9c281bf8 --- /dev/null +++ b/Source/VCExpr/NameClashResolver.cs @@ -0,0 +1,137 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// Visitor that establishes unique variable (or constant) names in a VCExpr. +// This is done by adding a counter as suffix if name clashes occur + +// TODO: also handle type variables here + +namespace Microsoft.Boogie.VCExprAST { + using TEHelperFuns = Microsoft.Boogie.TypeErasure.HelperFuns; + + public class UniqueNamer : ICloneable { + + public UniqueNamer() { + GlobalNames = new Dictionary (); + LocalNames = TEHelperFuns.ToList(new Dictionary () + as IDictionary); + UsedNames = new Dictionary (); + CurrentCounters = new Dictionary (); + GlobalPlusLocalNames = new Dictionary (); + } + + private UniqueNamer(UniqueNamer! namer) { + GlobalNames = new Dictionary (namer.GlobalNames); + + List!>! localNames = + new List!> (); + LocalNames = localNames; + + foreach (IDictionary! d in namer.LocalNames) + localNames.Add(new Dictionary (d)); + + UsedNames = new Dictionary (namer.UsedNames); + CurrentCounters = new Dictionary (namer.CurrentCounters); + GlobalPlusLocalNames = new Dictionary(namer.GlobalPlusLocalNames); + } + + public Object! Clone() { + return new UniqueNamer (this); + } + + //////////////////////////////////////////////////////////////////////////// + + private readonly IDictionary! GlobalNames; + private readonly List!>! LocalNames; + + // dictionary of all names that have already been used + // (locally or globally) + private readonly IDictionary! UsedNames; + private readonly IDictionary! CurrentCounters; + private readonly IDictionary! GlobalPlusLocalNames; + + //////////////////////////////////////////////////////////////////////////// + + public void PushScope() { + LocalNames.Add(new Dictionary ()); + } + + public void PopScope() { + LocalNames.RemoveAt(LocalNames.Count - 1); + } + + //////////////////////////////////////////////////////////////////////////// + + private string! NextFreeName(Object! thingie, string! baseName) { + string! candidate; + int counter; + + if (CurrentCounters.TryGetValue(baseName, out counter)) { + candidate = baseName + "@@" + counter; + counter = counter + 1; + } else { + candidate = baseName; + counter = 0; + } + + bool dummy; + while (UsedNames.TryGetValue(candidate, out dummy)) { + candidate = baseName + "@@" + counter; + counter = counter + 1; + } + + UsedNames.Add(candidate, true); + CurrentCounters[baseName] = counter; + GlobalPlusLocalNames[thingie] = candidate; + return candidate; + } + + // retrieve the name of a thingie; if it does not have a name yet, + // generate a unique name for it (as close as possible to its inherent + // name) and register it globally + public string! GetName(Object! thingie, string! inherentName) { + string res = this[thingie]; + + if (res != null) + return res; + + // if the object is not yet registered, create a name for it + res = NextFreeName(thingie, inherentName); + GlobalNames.Add(thingie, res); + + return res; + } + + [Pure] + public string this[Object! thingie] { get { + string res; + for (int i = LocalNames.Count - 1; i >= 0; --i) { + if (LocalNames[i].TryGetValue(thingie, out res)) + return res; + } + + GlobalNames.TryGetValue(thingie, out res); + return res; + } } + + public string! GetLocalName(Object! thingie, string! inherentName) { + string! res = NextFreeName(thingie, inherentName); + LocalNames[LocalNames.Count - 1][thingie] = res; + return res; + } + + public string! Lookup(Object! thingie) { + return GlobalPlusLocalNames[thingie]; + } + } +} diff --git a/Source/VCExpr/NameClashResolver.ssc b/Source/VCExpr/NameClashResolver.ssc deleted file mode 100644 index 9c281bf8..00000000 --- a/Source/VCExpr/NameClashResolver.ssc +++ /dev/null @@ -1,137 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// Visitor that establishes unique variable (or constant) names in a VCExpr. -// This is done by adding a counter as suffix if name clashes occur - -// TODO: also handle type variables here - -namespace Microsoft.Boogie.VCExprAST { - using TEHelperFuns = Microsoft.Boogie.TypeErasure.HelperFuns; - - public class UniqueNamer : ICloneable { - - public UniqueNamer() { - GlobalNames = new Dictionary (); - LocalNames = TEHelperFuns.ToList(new Dictionary () - as IDictionary); - UsedNames = new Dictionary (); - CurrentCounters = new Dictionary (); - GlobalPlusLocalNames = new Dictionary (); - } - - private UniqueNamer(UniqueNamer! namer) { - GlobalNames = new Dictionary (namer.GlobalNames); - - List!>! localNames = - new List!> (); - LocalNames = localNames; - - foreach (IDictionary! d in namer.LocalNames) - localNames.Add(new Dictionary (d)); - - UsedNames = new Dictionary (namer.UsedNames); - CurrentCounters = new Dictionary (namer.CurrentCounters); - GlobalPlusLocalNames = new Dictionary(namer.GlobalPlusLocalNames); - } - - public Object! Clone() { - return new UniqueNamer (this); - } - - //////////////////////////////////////////////////////////////////////////// - - private readonly IDictionary! GlobalNames; - private readonly List!>! LocalNames; - - // dictionary of all names that have already been used - // (locally or globally) - private readonly IDictionary! UsedNames; - private readonly IDictionary! CurrentCounters; - private readonly IDictionary! GlobalPlusLocalNames; - - //////////////////////////////////////////////////////////////////////////// - - public void PushScope() { - LocalNames.Add(new Dictionary ()); - } - - public void PopScope() { - LocalNames.RemoveAt(LocalNames.Count - 1); - } - - //////////////////////////////////////////////////////////////////////////// - - private string! NextFreeName(Object! thingie, string! baseName) { - string! candidate; - int counter; - - if (CurrentCounters.TryGetValue(baseName, out counter)) { - candidate = baseName + "@@" + counter; - counter = counter + 1; - } else { - candidate = baseName; - counter = 0; - } - - bool dummy; - while (UsedNames.TryGetValue(candidate, out dummy)) { - candidate = baseName + "@@" + counter; - counter = counter + 1; - } - - UsedNames.Add(candidate, true); - CurrentCounters[baseName] = counter; - GlobalPlusLocalNames[thingie] = candidate; - return candidate; - } - - // retrieve the name of a thingie; if it does not have a name yet, - // generate a unique name for it (as close as possible to its inherent - // name) and register it globally - public string! GetName(Object! thingie, string! inherentName) { - string res = this[thingie]; - - if (res != null) - return res; - - // if the object is not yet registered, create a name for it - res = NextFreeName(thingie, inherentName); - GlobalNames.Add(thingie, res); - - return res; - } - - [Pure] - public string this[Object! thingie] { get { - string res; - for (int i = LocalNames.Count - 1; i >= 0; --i) { - if (LocalNames[i].TryGetValue(thingie, out res)) - return res; - } - - GlobalNames.TryGetValue(thingie, out res); - return res; - } } - - public string! GetLocalName(Object! thingie, string! inherentName) { - string! res = NextFreeName(thingie, inherentName); - LocalNames[LocalNames.Count - 1][thingie] = res; - return res; - } - - public string! Lookup(Object! thingie) { - return GlobalPlusLocalNames[thingie]; - } - } -} diff --git a/Source/VCExpr/SimplifyLikeLineariser.cs b/Source/VCExpr/SimplifyLikeLineariser.cs new file mode 100644 index 00000000..30779f22 --- /dev/null +++ b/Source/VCExpr/SimplifyLikeLineariser.cs @@ -0,0 +1,844 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// a naive method to turn VCExprs into strings that can be fed into Simplify + +namespace Microsoft.Boogie.VCExprAST +{ + + // Options for the linearisation. Here one can choose, for instance, + // whether Simplify or Z3 output is to be produced + public abstract class LineariserOptions { + + public readonly bool AsTerm; + public abstract LineariserOptions! SetAsTerm(bool newVal); + + public abstract bool QuantifierIds { get; } + + public virtual bool UseWeights { get { return false; } } + + public virtual bool InverseImplies { get { return false; } } + + // whether to include type specifications in quantifiers + public abstract bool UseTypes { get; } + + public virtual CommandLineOptions.BvHandling Bitvectors { get { + return CommandLineOptions.BvHandling.None; + } } + + // variables representing formulas in let-bindings have to be + // printed in a different way than other variables + public virtual List! LetVariables { get { + return EmptyList; + } } + + public virtual LineariserOptions! AddLetVariable(VCExprVar! furtherVar) { + return this; + } + + public virtual LineariserOptions! AddLetVariables(List! furtherVars) { + return this; + } + + private static readonly List! EmptyList = new List(); + + public bool NativeBv { get { + return Bitvectors == CommandLineOptions.BvHandling.Z3Native; + } } + + public bool IntBv { get { + return Bitvectors == CommandLineOptions.BvHandling.ToInt; + } } + + //////////////////////////////////////////////////////////////////////////////////////// + + protected LineariserOptions(bool asTerm) { + this.AsTerm = asTerm; + } + + public static readonly LineariserOptions! SimplifyDefault = new SimplifyOptions (false); + internal static readonly LineariserOptions! SimplifyDefaultTerm = new SimplifyOptions (true); + + //////////////////////////////////////////////////////////////////////////////////////// + + private class SimplifyOptions : LineariserOptions { + internal SimplifyOptions(bool asTerm) { + base(asTerm); + } + public override bool QuantifierIds { get { + return false; + } } + public override bool UseTypes { get { + return false; + } } + public override LineariserOptions! SetAsTerm(bool newVal) { + if (newVal) + return SimplifyDefaultTerm; + else + return SimplifyDefault; + } + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + + // Lineariser for expressions. The result (bool) is currently not used for anything + public class SimplifyLikeExprLineariser : IVCExprVisitor { + + public static string! ToSimplifyString(VCExpr! e, UniqueNamer! namer) { + return ToString(e, LineariserOptions.SimplifyDefault, namer); + } + + public static string! ToString(VCExpr! e, LineariserOptions! options, + UniqueNamer! namer) { + StringWriter sw = new StringWriter(); + SimplifyLikeExprLineariser lin = new SimplifyLikeExprLineariser (sw, namer); + lin.Linearise(e, options); + return sw.ToString(); + } + + //////////////////////////////////////////////////////////////////////////////////////// + + private readonly TextWriter! wr; + private SimplifyLikeOpLineariser OpLinObject = null; + private IVCExprOpVisitor! OpLineariser { get { + if (OpLinObject == null) + OpLinObject = new SimplifyLikeOpLineariser (this, wr); + return OpLinObject; + } } + + internal readonly UniqueNamer! Namer; + + public SimplifyLikeExprLineariser(TextWriter! wr, UniqueNamer! namer) { + this.wr = wr; + this.Namer = namer; + } + + public void Linearise(VCExpr! expr, LineariserOptions! options) { + expr.Accept(this, options); + } + + public void LineariseAsTerm(VCExpr! expr, LineariserOptions! options) { + Linearise(expr, options.SetAsTerm(true)); + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public static string! MakeIdPrintable(string! s) { + // make sure that no keywords are used as identifiers + switch(s) { + case andName: + case orName: + case notName: + case impliesName: + case iffName: + case eqName: + case neqName: + case distinctName: + case TRUEName: + case FALSEName: + s = "nonkeyword_" + s; + break; + } + + if (CommandLineOptions.Clo.BracketIdsInVC == 0) { + // In this form, we go with any identifier, so we don't ever bother about brackets. + // Except: @true and @false are always written with brackets + return s; + } + bool looksLikeOperator = true; + bool looksLikeSimpleId = true; + bool useBrackets = false; + foreach (char ch in s) { + switch (ch) { + case '=': + case '<': + case '>': + case '+': + case '-': + case '*': + case '/': + case '%': + case ':': + // looks like operator, not simple id + looksLikeSimpleId = false; + break; + default: + if (Char.IsLetterOrDigit(ch)) { + // looks like simple id, not operator + looksLikeOperator = false; + } else { + // looks like neither operator nor simple id + looksLikeOperator = false; + looksLikeSimpleId = false; + } + break; + } + if (!looksLikeOperator && !looksLikeSimpleId) { + useBrackets = true; + break; + } + } + if (useBrackets) { + return "|" + s + "|"; + } else { + return s; + } + } + + private static string! TypeToStringHelper(Type! t) { + System.IO.StringWriter buffer = new System.IO.StringWriter(); + using (TokenTextWriter stream = new TokenTextWriter("", buffer, false)) { + t.Emit(stream); + } + return buffer.ToString(); + } + public static string! TypeToString(Type! t) { + if (t.IsBool) + return "$bool"; + else if (t.IsInt) + return "$int"; + else if (t.IsBv) + return "$bv" + t.BvBits; + else if (t.IsMap) + return TypeToStringHelper(t); + else { + // at this point, only the types U, T, and bitvector types should be left + if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.Monomorphic) + return "U"; + else + return TypeToStringHelper(t); + } + } + + public static string! BvConcatOpName(VCExprNAry! node) + requires node.Op is VCExprBvConcatOp; { + int bits1 = node[0].Type.BvBits; + int bits2 = node[1].Type.BvBits; + return "$bv" + (bits1 + bits2) + "_concat[" + bits1 + "." + bits2 + "]"; + } + + public static string! BvExtractOpName(VCExprNAry! node) + requires node.Op is VCExprBvExtractOp; { + VCExprBvExtractOp! op = (VCExprBvExtractOp)node.Op; + return "$bv" + node.Type.BvBits + "_extract" + op.Total + "[" + op.Start + ":" + op.End + "]"; + } + + public static string! StoreOpName(VCExprNAry! node) + requires node.Op is VCExprStoreOp; { + return "Store_" + TypeToString(node[0].Type); + } + + public static string! SelectOpName(VCExprNAry! node) + requires node.Op is VCExprSelectOp; { + return "Select_" + TypeToString(node[0].Type); + } + + internal void WriteId(string! s) { + wr.Write(MakeIdPrintable(s)); + } + + ///////////////////////////////////////////////////////////////////////////////////// + + /// + /// The name for logical conjunction in Simplify + /// + internal const string! andName = "AND"; // conjunction + internal const string! orName = "OR"; // disjunction + internal const string! notName = "NOT"; // negation + internal const string! impliesName = "IMPLIES"; // implication + internal const string! iffName = "IFF"; // logical equivalence + internal const string! eqName = "EQ"; // equality + internal const string! neqName = "NEQ"; // inequality + internal const string! lessName = "<"; + internal const string! greaterName = ">"; + internal const string! atmostName = "<="; + internal const string! atleastName = ">="; + internal const string! TRUEName = "TRUE"; // nullary predicate that is always true + internal const string! FALSEName = "FALSE"; // nullary predicate that is always false + internal const string! subtypeName = "<:"; + internal const string! subtypeArgsName = "<::"; + + internal const string! distinctName = "DISTINCT"; + /// + /// name of the main inclusion relation + /// + internal const string! boolTrueName = "|@true|"; + internal const string! boolFalseName = "|@false|"; + internal const string! boolAndName = "boolAnd"; + internal const string! boolOrName = "boolOr"; + internal const string! boolNotName = "boolNot"; + internal const string! termEqName = "anyEqual"; + internal const string! termNeqName = "anyNeq"; + internal const string! termLessName = "intLess"; + internal const string! termGreaterName = "intGreater"; + internal const string! termAtmostName = "intAtMost"; + internal const string! termAtleastName = "intAtLeast"; + internal const string! intAddName = "+"; + internal const string! intAddNameReflect = "Reflect$Add"; + internal const string! intSubName = "-"; + internal const string! intMulName = "*"; + internal const string! intDivName = "/"; + internal const string! intModName = "%"; + + internal void AssertAsTerm(string! x, LineariserOptions! options) { + if (!options.AsTerm) + System.Diagnostics.Debug.Fail("One should never write " + x + " as a formula!"); + } + + internal void AssertAsFormula(string! x, LineariserOptions! options) { + if (options.AsTerm) + System.Diagnostics.Debug.Fail("One should never write " + x + " as a term!"); + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public bool Visit(VCExprLiteral! node, LineariserOptions! options) { + if (options.AsTerm) { + + if (node == VCExpressionGenerator.True) + wr.Write(options.UseTypes ? TRUEName : boolTrueName); + else if (node == VCExpressionGenerator.False) + wr.Write(options.UseTypes ? FALSEName : boolFalseName); + else if (node is VCExprIntLit) { + wr.Write(((VCExprIntLit)node).Val); + } else + assert false; + + } else { + + if (node == VCExpressionGenerator.True) + wr.Write(TRUEName); + else if (node == VCExpressionGenerator.False) + wr.Write(FALSEName); + else if (node is VCExprIntLit) { + System.Diagnostics.Debug.Fail("One should never write IntLit as a predicate!"); + } else + assert false; + + } + + return true; + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public bool Visit(VCExprNAry! node, LineariserOptions! options) { + VCExprOp! op = node.Op; + + if (!options.AsTerm && + (op.Equals(VCExpressionGenerator.AndOp) || + op.Equals(VCExpressionGenerator.OrOp))) { + // handle these operators without recursion + + wr.Write("({0}", + op.Equals(VCExpressionGenerator.AndOp) ? andName : orName); + IEnumerator! enumerator = new VCExprNAryUniformOpEnumerator (node); + while (enumerator.MoveNext()) { + VCExprNAry naryExpr = enumerator.Current as VCExprNAry; + if (naryExpr == null || !naryExpr.Op.Equals(op)) { + wr.Write(" "); + Linearise((VCExpr!)enumerator.Current, options); + } + } + + wr.Write(")"); + + return true; + } + + return node.Accept(OpLineariser, options); + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public bool Visit(VCExprVar! node, LineariserOptions! options) { + string! printedName = Namer.GetName(node, node.Name); + + if (options.AsTerm || + // variables for formulas bound in a let-binding are never + // written as an equation + options.LetVariables.Contains(node) || + // if variables are properly typed, they cannot be written as + // equation either + options.UseTypes) { + WriteId(printedName); + } else { + wr.Write("({0} ", eqName); + WriteId(printedName); + wr.Write(" {0})", boolTrueName); + } + + return true; + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public bool Visit(VCExprQuantifier! node, LineariserOptions! options) { + AssertAsFormula(node.Quan.ToString(), options); + assert node.TypeParameters.Count == 0; + + Namer.PushScope(); try { + + string! kind = node.Quan == Quantifier.ALL ? "FORALL" : "EXISTS"; + wr.Write("({0} (", kind); + + for (int i = 0; i < node.BoundVars.Count; i++) + { + VCExprVar! var = node.BoundVars[i]; + string! printedName = Namer.GetLocalName(var, var.Name); + if (i != 0) + wr.Write(" "); + WriteId(printedName); + if (options.UseTypes) + wr.Write(" :TYPE {0}", TypeToString(var.Type)); + } + wr.Write(") "); + + WriteTriggers(node.Triggers, options); + + if (options.QuantifierIds) { + // only needed for Z3 + VCQuantifierInfos! infos = node.Infos; + if (infos.qid != null) { + wr.Write("(QID "); + wr.Write(infos.qid); + wr.Write(") "); + } + if (0 <= infos.uniqueId) { + wr.Write("(SKOLEMID "); + wr.Write(infos.uniqueId); + wr.Write(") "); + } + } + + if (options.UseWeights) { + int weight = QKeyValue.FindIntAttribute(node.Infos.attributes, "weight", 1); + if (weight != 1) { + wr.Write("(WEIGHT "); + wr.Write(weight); + wr.Write(") "); + } + } + + Linearise(node.Body, options); + wr.Write(")"); + + return true; + + } finally { + Namer.PopScope(); + } + } + + private void WriteTriggers(List! triggers, LineariserOptions! options) { + // first, count how many neg/pos triggers there are + int negTriggers = 0; + int posTriggers = 0; + foreach (VCTrigger! vcTrig in triggers) { + if (vcTrig.Pos) { + posTriggers++; + } else { + negTriggers++; + } + } + + if (posTriggers > 0) { + wr.Write("(PATS"); + foreach (VCTrigger! vcTrig in triggers) { + if (vcTrig.Pos) { + if (vcTrig.Exprs.Count > 1) { + wr.Write(" (MPAT"); + } + foreach (VCExpr! e in vcTrig.Exprs) { + wr.Write(" "); + LineariseAsTerm(e, options); + } + if (vcTrig.Exprs.Count > 1) { + wr.Write(")"); + } + } + } + wr.Write(") "); + } else if (negTriggers > 0) { + // if also positive triggers are given, the SMT solver (at least Z3) + // will ignore the negative patterns and output a warning. Therefore + // we never specify both negative and positive triggers + wr.Write("(NOPATS"); + foreach (VCTrigger! vcTrig in triggers) { + if (!vcTrig.Pos) { + wr.Write(" "); + assert vcTrig.Exprs.Count == 1; + LineariseAsTerm(vcTrig.Exprs[0], options); + } + } + wr.Write(") "); + } + + } + + ///////////////////////////////////////////////////////////////////////////////////// + + public bool Visit(VCExprLet! node, LineariserOptions! options) { + Namer.PushScope(); try { + + wr.Write("(LET ("); + + LineariserOptions! optionsWithVars = options.AddLetVariables(node.BoundVars); + + string s = "("; + foreach (VCExprLetBinding! b in node) { + wr.Write(s); + string! printedName = Namer.GetLocalName(b.V, b.V.Name); + + bool formula = b.V.Type.IsBool; + if (formula) + wr.Write("FORMULA "); + else + wr.Write("TERM "); + WriteId(printedName); + wr.Write(" "); + Linearise(b.E, optionsWithVars.SetAsTerm(!formula)); + wr.Write(")"); + s = " ("; + } + wr.Write(") "); + Linearise(node.Body, optionsWithVars); + wr.Write(")"); + + return true; + + } finally { + Namer.PopScope(); + } + } + + ///////////////////////////////////////////////////////////////////////////////////// + + // Lineariser for operator terms. The result (bool) is currently not used for anything + internal class SimplifyLikeOpLineariser : IVCExprOpVisitor { + private readonly SimplifyLikeExprLineariser! ExprLineariser; + private readonly TextWriter! wr; + + public SimplifyLikeOpLineariser(SimplifyLikeExprLineariser! ExprLineariser, TextWriter! wr) { + this.ExprLineariser = ExprLineariser; + this.wr = wr; + } + + /////////////////////////////////////////////////////////////////////////////////// + + private void WriteApplication(string! op, IEnumerable! args, + LineariserOptions! options, + bool argsAsTerms) { + WriteApplication(op, op, args, options, argsAsTerms); + } + + private void WriteApplication(string! op, IEnumerable! args, + LineariserOptions! options) { + WriteApplication(op, op, args, options, options.AsTerm); + } + + private void WriteTermApplication(string! op, IEnumerable! args, + LineariserOptions! options) { + ExprLineariser.AssertAsTerm(op, options); + WriteApplication(op, op, args, options, options.AsTerm); + } + + private void WriteApplication(string! termOp, string! predOp, + IEnumerable! args, LineariserOptions! options) { + WriteApplication(termOp, predOp, args, options, options.AsTerm); + } + + private void WriteApplication(string! termOp, string! predOp, + IEnumerable! args, LineariserOptions! options, + // change the AsTerm option for the arguments? + bool argsAsTerms) { + wr.Write("({0}", options.AsTerm ? termOp : predOp); + + LineariserOptions! newOptions = options.SetAsTerm(argsAsTerms); + foreach (VCExpr! e in args) { + wr.Write(" "); + ExprLineariser.Linearise(e, newOptions); + } + + wr.Write(")"); + } + + // write an application that can only be a term. + // if the expression is supposed to be printed as a formula, + // it is turned into an equation (EQ (f args) |@true|) + private void WriteApplicationTermOnly(string! termOp, + IEnumerable! args, LineariserOptions! options) { + if (!options.AsTerm) + // Write: (EQ (f args) |@true|) + // where "args" are written as terms + wr.Write("({0} ", eqName); + + WriteApplication(termOp, args, options, true); + + if (!options.AsTerm) + wr.Write(" {0})", boolTrueName); + } + + /////////////////////////////////////////////////////////////////////////////////// + + public bool VisitNotOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(boolNotName, notName, node, options); // arguments can be both terms and formulas + return true; + } + + public bool VisitEqOp (VCExprNAry! node, LineariserOptions! options) { + if (options.AsTerm) { + // use equality on terms, also if the arguments have type bool + WriteApplication(termEqName, node, options); + } else { + if (node[0].Type.IsBool) { + assert node[1].Type.IsBool; + // use equivalence + WriteApplication(iffName, node, options); + } else { + assert !node[1].Type.IsBool; + // use equality and write the arguments as terms + WriteApplication(eqName, node, options, true); + } + } + + return true; + } + + public bool VisitNeqOp (VCExprNAry! node, LineariserOptions! options) { + if (options.AsTerm) { + // use equality on terms, also if the arguments have type bool + WriteApplication(termNeqName, node, options); + } else { + if (node[0].Type.IsBool) { + assert node[1].Type.IsBool; + // use equivalence and negate the whole thing + wr.Write("({0} ", notName); + WriteApplication(iffName, node, options); + wr.Write(")"); + } else { + // use equality and write the arguments as terms + WriteApplication(neqName, node, options, true); + } + } + + return true; + } + + public bool VisitAndOp (VCExprNAry! node, LineariserOptions! options) { + assert options.AsTerm; + WriteApplication(boolAndName, andName, node, options); // arguments can be both terms and formulas + return true; + } + + public bool VisitOrOp (VCExprNAry! node, LineariserOptions! options) { + assert options.AsTerm; + WriteApplication(boolOrName, orName, node, options); // arguments can be both terms and formulas + return true; + } + + public bool VisitImpliesOp (VCExprNAry! node, LineariserOptions! options) { + if (options.AsTerm) { + wr.Write("({0} ({1} ", boolOrName, boolNotName); + ExprLineariser.Linearise(node[0], options); + wr.Write(") "); + ExprLineariser.Linearise(node[1], options); + wr.Write(")"); + } else if (options.InverseImplies) { + wr.Write("({0} ", orName); + ExprLineariser.Linearise(node[1], options); + wr.Write(" ({0} ", notName); + ExprLineariser.Linearise(node[0], options); + wr.Write("))"); + } else { + WriteApplication(impliesName, node, options); + } + return true; + } + + public bool VisitDistinctOp (VCExprNAry! node, LineariserOptions! options) { + ExprLineariser.AssertAsFormula(distinctName, options); + + if (node.Length < 2) { + ExprLineariser.Linearise(VCExpressionGenerator.True, options); + } else { + wr.Write("({0}", distinctName); + foreach (VCExpr! e in node) { + wr.Write(" "); + ExprLineariser.LineariseAsTerm(e, options); + } + wr.Write(")"); + } + + return true; + } + + public bool VisitLabelOp (VCExprNAry! node, LineariserOptions! options) { + VCExprLabelOp! op = (VCExprLabelOp)node.Op; + wr.Write(String.Format("({0} |{1}| ", op.pos ? "LBLPOS" : "LBLNEG", op.label)); + ExprLineariser.Linearise(node[0], options); wr.Write(")"); + return true; + } + + public bool VisitSelectOp (VCExprNAry! node, LineariserOptions! options) { + wr.Write("(" + SelectOpName(node)); + foreach (VCExpr! e in node) { + wr.Write(" "); + ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); + } + wr.Write(")"); + return true; + } + + public bool VisitStoreOp (VCExprNAry! node, LineariserOptions! options) { + wr.Write("(" + StoreOpName(node)); + foreach (VCExpr! e in node) { + wr.Write(" "); + ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); + } + wr.Write(")"); + return true; + } + + public bool VisitBvOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication("$make_bv" + node.Type.BvBits, node, options); + return true; + } + + public bool VisitBvExtractOp(VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(BvExtractOpName(node), node, options); + return true; + } + + public bool VisitBvConcatOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(BvConcatOpName(node), node, options); + return true; + } + + public bool VisitIfThenElseOp (VCExprNAry! node, LineariserOptions! options) { + + wr.Write("(ITE "); + ExprLineariser.Linearise(node[0], options.SetAsTerm(false)); + wr.Write(" "); + ExprLineariser.Linearise(node[1], options); + wr.Write(" "); + ExprLineariser.Linearise(node[2], options); + wr.Write(")"); + + return true; + } + + public bool VisitCustomOp (VCExprNAry! node, LineariserOptions! options) { + VCExprCustomOp op = (VCExprCustomOp)node.Op; + wr.Write("({0}", op.Name); + foreach (VCExpr arg in node) { + wr.Write(" "); + ExprLineariser.Linearise(arg, options); + } + wr.Write(")"); + return true; + } + + public bool VisitAddOp (VCExprNAry! node, LineariserOptions! options) { + if (CommandLineOptions.Clo.ReflectAdd) { + WriteTermApplication(intAddNameReflect, node, options); + } else { + WriteTermApplication(intAddName, node, options); + } + return true; + } + + public bool VisitSubOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(intSubName, node, options); + return true; + } + + public bool VisitMulOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(intMulName, node, options); + return true; + } + + public bool VisitDivOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(intDivName, node, options); + return true; + } + + public bool VisitModOp (VCExprNAry! node, LineariserOptions! options) { + WriteTermApplication(intModName, node, options); + return true; + } + + public bool VisitLtOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(termLessName, lessName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitLeOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(termAtmostName, atmostName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitGtOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(termGreaterName, greaterName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitGeOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(termAtleastName, atleastName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitSubtypeOp (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(subtypeName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitSubtype3Op (VCExprNAry! node, LineariserOptions! options) { + WriteApplication(subtypeArgsName, node, options, true); // arguments are always terms + return true; + } + + public bool VisitBoogieFunctionOp (VCExprNAry! node, LineariserOptions! options) { + VCExprBoogieFunctionOp! op = (VCExprBoogieFunctionOp)node.Op; + string! funcName = op.Func.Name; + string? bvzName = op.Func.FindStringAttribute("external"); + string! printedName = ExprLineariser.Namer.GetName(op.Func, funcName); + if (bvzName != null) printedName = bvzName; + + if (options.UseTypes) { + // we use term notation for arguments whose type is not bool, and + // formula notation for boolean arguments + + wr.Write("("); + ExprLineariser.WriteId(printedName); + + foreach (VCExpr! e in node) { + wr.Write(" "); + ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); + } + + wr.Write(")"); + } else { + // arguments are always terms + WriteApplicationTermOnly(SimplifyLikeExprLineariser.MakeIdPrintable(printedName), + node, options); + } + return true; + } + + } + } + +} diff --git a/Source/VCExpr/SimplifyLikeLineariser.ssc b/Source/VCExpr/SimplifyLikeLineariser.ssc deleted file mode 100644 index 30779f22..00000000 --- a/Source/VCExpr/SimplifyLikeLineariser.ssc +++ /dev/null @@ -1,844 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// a naive method to turn VCExprs into strings that can be fed into Simplify - -namespace Microsoft.Boogie.VCExprAST -{ - - // Options for the linearisation. Here one can choose, for instance, - // whether Simplify or Z3 output is to be produced - public abstract class LineariserOptions { - - public readonly bool AsTerm; - public abstract LineariserOptions! SetAsTerm(bool newVal); - - public abstract bool QuantifierIds { get; } - - public virtual bool UseWeights { get { return false; } } - - public virtual bool InverseImplies { get { return false; } } - - // whether to include type specifications in quantifiers - public abstract bool UseTypes { get; } - - public virtual CommandLineOptions.BvHandling Bitvectors { get { - return CommandLineOptions.BvHandling.None; - } } - - // variables representing formulas in let-bindings have to be - // printed in a different way than other variables - public virtual List! LetVariables { get { - return EmptyList; - } } - - public virtual LineariserOptions! AddLetVariable(VCExprVar! furtherVar) { - return this; - } - - public virtual LineariserOptions! AddLetVariables(List! furtherVars) { - return this; - } - - private static readonly List! EmptyList = new List(); - - public bool NativeBv { get { - return Bitvectors == CommandLineOptions.BvHandling.Z3Native; - } } - - public bool IntBv { get { - return Bitvectors == CommandLineOptions.BvHandling.ToInt; - } } - - //////////////////////////////////////////////////////////////////////////////////////// - - protected LineariserOptions(bool asTerm) { - this.AsTerm = asTerm; - } - - public static readonly LineariserOptions! SimplifyDefault = new SimplifyOptions (false); - internal static readonly LineariserOptions! SimplifyDefaultTerm = new SimplifyOptions (true); - - //////////////////////////////////////////////////////////////////////////////////////// - - private class SimplifyOptions : LineariserOptions { - internal SimplifyOptions(bool asTerm) { - base(asTerm); - } - public override bool QuantifierIds { get { - return false; - } } - public override bool UseTypes { get { - return false; - } } - public override LineariserOptions! SetAsTerm(bool newVal) { - if (newVal) - return SimplifyDefaultTerm; - else - return SimplifyDefault; - } - } - } - - //////////////////////////////////////////////////////////////////////////////////////// - - // Lineariser for expressions. The result (bool) is currently not used for anything - public class SimplifyLikeExprLineariser : IVCExprVisitor { - - public static string! ToSimplifyString(VCExpr! e, UniqueNamer! namer) { - return ToString(e, LineariserOptions.SimplifyDefault, namer); - } - - public static string! ToString(VCExpr! e, LineariserOptions! options, - UniqueNamer! namer) { - StringWriter sw = new StringWriter(); - SimplifyLikeExprLineariser lin = new SimplifyLikeExprLineariser (sw, namer); - lin.Linearise(e, options); - return sw.ToString(); - } - - //////////////////////////////////////////////////////////////////////////////////////// - - private readonly TextWriter! wr; - private SimplifyLikeOpLineariser OpLinObject = null; - private IVCExprOpVisitor! OpLineariser { get { - if (OpLinObject == null) - OpLinObject = new SimplifyLikeOpLineariser (this, wr); - return OpLinObject; - } } - - internal readonly UniqueNamer! Namer; - - public SimplifyLikeExprLineariser(TextWriter! wr, UniqueNamer! namer) { - this.wr = wr; - this.Namer = namer; - } - - public void Linearise(VCExpr! expr, LineariserOptions! options) { - expr.Accept(this, options); - } - - public void LineariseAsTerm(VCExpr! expr, LineariserOptions! options) { - Linearise(expr, options.SetAsTerm(true)); - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public static string! MakeIdPrintable(string! s) { - // make sure that no keywords are used as identifiers - switch(s) { - case andName: - case orName: - case notName: - case impliesName: - case iffName: - case eqName: - case neqName: - case distinctName: - case TRUEName: - case FALSEName: - s = "nonkeyword_" + s; - break; - } - - if (CommandLineOptions.Clo.BracketIdsInVC == 0) { - // In this form, we go with any identifier, so we don't ever bother about brackets. - // Except: @true and @false are always written with brackets - return s; - } - bool looksLikeOperator = true; - bool looksLikeSimpleId = true; - bool useBrackets = false; - foreach (char ch in s) { - switch (ch) { - case '=': - case '<': - case '>': - case '+': - case '-': - case '*': - case '/': - case '%': - case ':': - // looks like operator, not simple id - looksLikeSimpleId = false; - break; - default: - if (Char.IsLetterOrDigit(ch)) { - // looks like simple id, not operator - looksLikeOperator = false; - } else { - // looks like neither operator nor simple id - looksLikeOperator = false; - looksLikeSimpleId = false; - } - break; - } - if (!looksLikeOperator && !looksLikeSimpleId) { - useBrackets = true; - break; - } - } - if (useBrackets) { - return "|" + s + "|"; - } else { - return s; - } - } - - private static string! TypeToStringHelper(Type! t) { - System.IO.StringWriter buffer = new System.IO.StringWriter(); - using (TokenTextWriter stream = new TokenTextWriter("", buffer, false)) { - t.Emit(stream); - } - return buffer.ToString(); - } - public static string! TypeToString(Type! t) { - if (t.IsBool) - return "$bool"; - else if (t.IsInt) - return "$int"; - else if (t.IsBv) - return "$bv" + t.BvBits; - else if (t.IsMap) - return TypeToStringHelper(t); - else { - // at this point, only the types U, T, and bitvector types should be left - if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.Monomorphic) - return "U"; - else - return TypeToStringHelper(t); - } - } - - public static string! BvConcatOpName(VCExprNAry! node) - requires node.Op is VCExprBvConcatOp; { - int bits1 = node[0].Type.BvBits; - int bits2 = node[1].Type.BvBits; - return "$bv" + (bits1 + bits2) + "_concat[" + bits1 + "." + bits2 + "]"; - } - - public static string! BvExtractOpName(VCExprNAry! node) - requires node.Op is VCExprBvExtractOp; { - VCExprBvExtractOp! op = (VCExprBvExtractOp)node.Op; - return "$bv" + node.Type.BvBits + "_extract" + op.Total + "[" + op.Start + ":" + op.End + "]"; - } - - public static string! StoreOpName(VCExprNAry! node) - requires node.Op is VCExprStoreOp; { - return "Store_" + TypeToString(node[0].Type); - } - - public static string! SelectOpName(VCExprNAry! node) - requires node.Op is VCExprSelectOp; { - return "Select_" + TypeToString(node[0].Type); - } - - internal void WriteId(string! s) { - wr.Write(MakeIdPrintable(s)); - } - - ///////////////////////////////////////////////////////////////////////////////////// - - /// - /// The name for logical conjunction in Simplify - /// - internal const string! andName = "AND"; // conjunction - internal const string! orName = "OR"; // disjunction - internal const string! notName = "NOT"; // negation - internal const string! impliesName = "IMPLIES"; // implication - internal const string! iffName = "IFF"; // logical equivalence - internal const string! eqName = "EQ"; // equality - internal const string! neqName = "NEQ"; // inequality - internal const string! lessName = "<"; - internal const string! greaterName = ">"; - internal const string! atmostName = "<="; - internal const string! atleastName = ">="; - internal const string! TRUEName = "TRUE"; // nullary predicate that is always true - internal const string! FALSEName = "FALSE"; // nullary predicate that is always false - internal const string! subtypeName = "<:"; - internal const string! subtypeArgsName = "<::"; - - internal const string! distinctName = "DISTINCT"; - /// - /// name of the main inclusion relation - /// - internal const string! boolTrueName = "|@true|"; - internal const string! boolFalseName = "|@false|"; - internal const string! boolAndName = "boolAnd"; - internal const string! boolOrName = "boolOr"; - internal const string! boolNotName = "boolNot"; - internal const string! termEqName = "anyEqual"; - internal const string! termNeqName = "anyNeq"; - internal const string! termLessName = "intLess"; - internal const string! termGreaterName = "intGreater"; - internal const string! termAtmostName = "intAtMost"; - internal const string! termAtleastName = "intAtLeast"; - internal const string! intAddName = "+"; - internal const string! intAddNameReflect = "Reflect$Add"; - internal const string! intSubName = "-"; - internal const string! intMulName = "*"; - internal const string! intDivName = "/"; - internal const string! intModName = "%"; - - internal void AssertAsTerm(string! x, LineariserOptions! options) { - if (!options.AsTerm) - System.Diagnostics.Debug.Fail("One should never write " + x + " as a formula!"); - } - - internal void AssertAsFormula(string! x, LineariserOptions! options) { - if (options.AsTerm) - System.Diagnostics.Debug.Fail("One should never write " + x + " as a term!"); - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public bool Visit(VCExprLiteral! node, LineariserOptions! options) { - if (options.AsTerm) { - - if (node == VCExpressionGenerator.True) - wr.Write(options.UseTypes ? TRUEName : boolTrueName); - else if (node == VCExpressionGenerator.False) - wr.Write(options.UseTypes ? FALSEName : boolFalseName); - else if (node is VCExprIntLit) { - wr.Write(((VCExprIntLit)node).Val); - } else - assert false; - - } else { - - if (node == VCExpressionGenerator.True) - wr.Write(TRUEName); - else if (node == VCExpressionGenerator.False) - wr.Write(FALSEName); - else if (node is VCExprIntLit) { - System.Diagnostics.Debug.Fail("One should never write IntLit as a predicate!"); - } else - assert false; - - } - - return true; - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public bool Visit(VCExprNAry! node, LineariserOptions! options) { - VCExprOp! op = node.Op; - - if (!options.AsTerm && - (op.Equals(VCExpressionGenerator.AndOp) || - op.Equals(VCExpressionGenerator.OrOp))) { - // handle these operators without recursion - - wr.Write("({0}", - op.Equals(VCExpressionGenerator.AndOp) ? andName : orName); - IEnumerator! enumerator = new VCExprNAryUniformOpEnumerator (node); - while (enumerator.MoveNext()) { - VCExprNAry naryExpr = enumerator.Current as VCExprNAry; - if (naryExpr == null || !naryExpr.Op.Equals(op)) { - wr.Write(" "); - Linearise((VCExpr!)enumerator.Current, options); - } - } - - wr.Write(")"); - - return true; - } - - return node.Accept(OpLineariser, options); - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public bool Visit(VCExprVar! node, LineariserOptions! options) { - string! printedName = Namer.GetName(node, node.Name); - - if (options.AsTerm || - // variables for formulas bound in a let-binding are never - // written as an equation - options.LetVariables.Contains(node) || - // if variables are properly typed, they cannot be written as - // equation either - options.UseTypes) { - WriteId(printedName); - } else { - wr.Write("({0} ", eqName); - WriteId(printedName); - wr.Write(" {0})", boolTrueName); - } - - return true; - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public bool Visit(VCExprQuantifier! node, LineariserOptions! options) { - AssertAsFormula(node.Quan.ToString(), options); - assert node.TypeParameters.Count == 0; - - Namer.PushScope(); try { - - string! kind = node.Quan == Quantifier.ALL ? "FORALL" : "EXISTS"; - wr.Write("({0} (", kind); - - for (int i = 0; i < node.BoundVars.Count; i++) - { - VCExprVar! var = node.BoundVars[i]; - string! printedName = Namer.GetLocalName(var, var.Name); - if (i != 0) - wr.Write(" "); - WriteId(printedName); - if (options.UseTypes) - wr.Write(" :TYPE {0}", TypeToString(var.Type)); - } - wr.Write(") "); - - WriteTriggers(node.Triggers, options); - - if (options.QuantifierIds) { - // only needed for Z3 - VCQuantifierInfos! infos = node.Infos; - if (infos.qid != null) { - wr.Write("(QID "); - wr.Write(infos.qid); - wr.Write(") "); - } - if (0 <= infos.uniqueId) { - wr.Write("(SKOLEMID "); - wr.Write(infos.uniqueId); - wr.Write(") "); - } - } - - if (options.UseWeights) { - int weight = QKeyValue.FindIntAttribute(node.Infos.attributes, "weight", 1); - if (weight != 1) { - wr.Write("(WEIGHT "); - wr.Write(weight); - wr.Write(") "); - } - } - - Linearise(node.Body, options); - wr.Write(")"); - - return true; - - } finally { - Namer.PopScope(); - } - } - - private void WriteTriggers(List! triggers, LineariserOptions! options) { - // first, count how many neg/pos triggers there are - int negTriggers = 0; - int posTriggers = 0; - foreach (VCTrigger! vcTrig in triggers) { - if (vcTrig.Pos) { - posTriggers++; - } else { - negTriggers++; - } - } - - if (posTriggers > 0) { - wr.Write("(PATS"); - foreach (VCTrigger! vcTrig in triggers) { - if (vcTrig.Pos) { - if (vcTrig.Exprs.Count > 1) { - wr.Write(" (MPAT"); - } - foreach (VCExpr! e in vcTrig.Exprs) { - wr.Write(" "); - LineariseAsTerm(e, options); - } - if (vcTrig.Exprs.Count > 1) { - wr.Write(")"); - } - } - } - wr.Write(") "); - } else if (negTriggers > 0) { - // if also positive triggers are given, the SMT solver (at least Z3) - // will ignore the negative patterns and output a warning. Therefore - // we never specify both negative and positive triggers - wr.Write("(NOPATS"); - foreach (VCTrigger! vcTrig in triggers) { - if (!vcTrig.Pos) { - wr.Write(" "); - assert vcTrig.Exprs.Count == 1; - LineariseAsTerm(vcTrig.Exprs[0], options); - } - } - wr.Write(") "); - } - - } - - ///////////////////////////////////////////////////////////////////////////////////// - - public bool Visit(VCExprLet! node, LineariserOptions! options) { - Namer.PushScope(); try { - - wr.Write("(LET ("); - - LineariserOptions! optionsWithVars = options.AddLetVariables(node.BoundVars); - - string s = "("; - foreach (VCExprLetBinding! b in node) { - wr.Write(s); - string! printedName = Namer.GetLocalName(b.V, b.V.Name); - - bool formula = b.V.Type.IsBool; - if (formula) - wr.Write("FORMULA "); - else - wr.Write("TERM "); - WriteId(printedName); - wr.Write(" "); - Linearise(b.E, optionsWithVars.SetAsTerm(!formula)); - wr.Write(")"); - s = " ("; - } - wr.Write(") "); - Linearise(node.Body, optionsWithVars); - wr.Write(")"); - - return true; - - } finally { - Namer.PopScope(); - } - } - - ///////////////////////////////////////////////////////////////////////////////////// - - // Lineariser for operator terms. The result (bool) is currently not used for anything - internal class SimplifyLikeOpLineariser : IVCExprOpVisitor { - private readonly SimplifyLikeExprLineariser! ExprLineariser; - private readonly TextWriter! wr; - - public SimplifyLikeOpLineariser(SimplifyLikeExprLineariser! ExprLineariser, TextWriter! wr) { - this.ExprLineariser = ExprLineariser; - this.wr = wr; - } - - /////////////////////////////////////////////////////////////////////////////////// - - private void WriteApplication(string! op, IEnumerable! args, - LineariserOptions! options, - bool argsAsTerms) { - WriteApplication(op, op, args, options, argsAsTerms); - } - - private void WriteApplication(string! op, IEnumerable! args, - LineariserOptions! options) { - WriteApplication(op, op, args, options, options.AsTerm); - } - - private void WriteTermApplication(string! op, IEnumerable! args, - LineariserOptions! options) { - ExprLineariser.AssertAsTerm(op, options); - WriteApplication(op, op, args, options, options.AsTerm); - } - - private void WriteApplication(string! termOp, string! predOp, - IEnumerable! args, LineariserOptions! options) { - WriteApplication(termOp, predOp, args, options, options.AsTerm); - } - - private void WriteApplication(string! termOp, string! predOp, - IEnumerable! args, LineariserOptions! options, - // change the AsTerm option for the arguments? - bool argsAsTerms) { - wr.Write("({0}", options.AsTerm ? termOp : predOp); - - LineariserOptions! newOptions = options.SetAsTerm(argsAsTerms); - foreach (VCExpr! e in args) { - wr.Write(" "); - ExprLineariser.Linearise(e, newOptions); - } - - wr.Write(")"); - } - - // write an application that can only be a term. - // if the expression is supposed to be printed as a formula, - // it is turned into an equation (EQ (f args) |@true|) - private void WriteApplicationTermOnly(string! termOp, - IEnumerable! args, LineariserOptions! options) { - if (!options.AsTerm) - // Write: (EQ (f args) |@true|) - // where "args" are written as terms - wr.Write("({0} ", eqName); - - WriteApplication(termOp, args, options, true); - - if (!options.AsTerm) - wr.Write(" {0})", boolTrueName); - } - - /////////////////////////////////////////////////////////////////////////////////// - - public bool VisitNotOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(boolNotName, notName, node, options); // arguments can be both terms and formulas - return true; - } - - public bool VisitEqOp (VCExprNAry! node, LineariserOptions! options) { - if (options.AsTerm) { - // use equality on terms, also if the arguments have type bool - WriteApplication(termEqName, node, options); - } else { - if (node[0].Type.IsBool) { - assert node[1].Type.IsBool; - // use equivalence - WriteApplication(iffName, node, options); - } else { - assert !node[1].Type.IsBool; - // use equality and write the arguments as terms - WriteApplication(eqName, node, options, true); - } - } - - return true; - } - - public bool VisitNeqOp (VCExprNAry! node, LineariserOptions! options) { - if (options.AsTerm) { - // use equality on terms, also if the arguments have type bool - WriteApplication(termNeqName, node, options); - } else { - if (node[0].Type.IsBool) { - assert node[1].Type.IsBool; - // use equivalence and negate the whole thing - wr.Write("({0} ", notName); - WriteApplication(iffName, node, options); - wr.Write(")"); - } else { - // use equality and write the arguments as terms - WriteApplication(neqName, node, options, true); - } - } - - return true; - } - - public bool VisitAndOp (VCExprNAry! node, LineariserOptions! options) { - assert options.AsTerm; - WriteApplication(boolAndName, andName, node, options); // arguments can be both terms and formulas - return true; - } - - public bool VisitOrOp (VCExprNAry! node, LineariserOptions! options) { - assert options.AsTerm; - WriteApplication(boolOrName, orName, node, options); // arguments can be both terms and formulas - return true; - } - - public bool VisitImpliesOp (VCExprNAry! node, LineariserOptions! options) { - if (options.AsTerm) { - wr.Write("({0} ({1} ", boolOrName, boolNotName); - ExprLineariser.Linearise(node[0], options); - wr.Write(") "); - ExprLineariser.Linearise(node[1], options); - wr.Write(")"); - } else if (options.InverseImplies) { - wr.Write("({0} ", orName); - ExprLineariser.Linearise(node[1], options); - wr.Write(" ({0} ", notName); - ExprLineariser.Linearise(node[0], options); - wr.Write("))"); - } else { - WriteApplication(impliesName, node, options); - } - return true; - } - - public bool VisitDistinctOp (VCExprNAry! node, LineariserOptions! options) { - ExprLineariser.AssertAsFormula(distinctName, options); - - if (node.Length < 2) { - ExprLineariser.Linearise(VCExpressionGenerator.True, options); - } else { - wr.Write("({0}", distinctName); - foreach (VCExpr! e in node) { - wr.Write(" "); - ExprLineariser.LineariseAsTerm(e, options); - } - wr.Write(")"); - } - - return true; - } - - public bool VisitLabelOp (VCExprNAry! node, LineariserOptions! options) { - VCExprLabelOp! op = (VCExprLabelOp)node.Op; - wr.Write(String.Format("({0} |{1}| ", op.pos ? "LBLPOS" : "LBLNEG", op.label)); - ExprLineariser.Linearise(node[0], options); wr.Write(")"); - return true; - } - - public bool VisitSelectOp (VCExprNAry! node, LineariserOptions! options) { - wr.Write("(" + SelectOpName(node)); - foreach (VCExpr! e in node) { - wr.Write(" "); - ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); - } - wr.Write(")"); - return true; - } - - public bool VisitStoreOp (VCExprNAry! node, LineariserOptions! options) { - wr.Write("(" + StoreOpName(node)); - foreach (VCExpr! e in node) { - wr.Write(" "); - ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); - } - wr.Write(")"); - return true; - } - - public bool VisitBvOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication("$make_bv" + node.Type.BvBits, node, options); - return true; - } - - public bool VisitBvExtractOp(VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(BvExtractOpName(node), node, options); - return true; - } - - public bool VisitBvConcatOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(BvConcatOpName(node), node, options); - return true; - } - - public bool VisitIfThenElseOp (VCExprNAry! node, LineariserOptions! options) { - - wr.Write("(ITE "); - ExprLineariser.Linearise(node[0], options.SetAsTerm(false)); - wr.Write(" "); - ExprLineariser.Linearise(node[1], options); - wr.Write(" "); - ExprLineariser.Linearise(node[2], options); - wr.Write(")"); - - return true; - } - - public bool VisitCustomOp (VCExprNAry! node, LineariserOptions! options) { - VCExprCustomOp op = (VCExprCustomOp)node.Op; - wr.Write("({0}", op.Name); - foreach (VCExpr arg in node) { - wr.Write(" "); - ExprLineariser.Linearise(arg, options); - } - wr.Write(")"); - return true; - } - - public bool VisitAddOp (VCExprNAry! node, LineariserOptions! options) { - if (CommandLineOptions.Clo.ReflectAdd) { - WriteTermApplication(intAddNameReflect, node, options); - } else { - WriteTermApplication(intAddName, node, options); - } - return true; - } - - public bool VisitSubOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(intSubName, node, options); - return true; - } - - public bool VisitMulOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(intMulName, node, options); - return true; - } - - public bool VisitDivOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(intDivName, node, options); - return true; - } - - public bool VisitModOp (VCExprNAry! node, LineariserOptions! options) { - WriteTermApplication(intModName, node, options); - return true; - } - - public bool VisitLtOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(termLessName, lessName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitLeOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(termAtmostName, atmostName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitGtOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(termGreaterName, greaterName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitGeOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(termAtleastName, atleastName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitSubtypeOp (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(subtypeName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitSubtype3Op (VCExprNAry! node, LineariserOptions! options) { - WriteApplication(subtypeArgsName, node, options, true); // arguments are always terms - return true; - } - - public bool VisitBoogieFunctionOp (VCExprNAry! node, LineariserOptions! options) { - VCExprBoogieFunctionOp! op = (VCExprBoogieFunctionOp)node.Op; - string! funcName = op.Func.Name; - string? bvzName = op.Func.FindStringAttribute("external"); - string! printedName = ExprLineariser.Namer.GetName(op.Func, funcName); - if (bvzName != null) printedName = bvzName; - - if (options.UseTypes) { - // we use term notation for arguments whose type is not bool, and - // formula notation for boolean arguments - - wr.Write("("); - ExprLineariser.WriteId(printedName); - - foreach (VCExpr! e in node) { - wr.Write(" "); - ExprLineariser.Linearise(e, options.SetAsTerm(!e.Type.IsBool)); - } - - wr.Write(")"); - } else { - // arguments are always terms - WriteApplicationTermOnly(SimplifyLikeExprLineariser.MakeIdPrintable(printedName), - node, options); - } - return true; - } - - } - } - -} diff --git a/Source/VCExpr/TermFormulaFlattening.cs b/Source/VCExpr/TermFormulaFlattening.cs new file mode 100644 index 00000000..bfb8cb3a --- /dev/null +++ b/Source/VCExpr/TermFormulaFlattening.cs @@ -0,0 +1,222 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// Ensure that no formulas (expressions of type boolean that are not +// just a variable) occur with terms (expressions of some other +// type). This is done by introducing let-binders for boolean +// variables. + +namespace Microsoft.Boogie.VCExprAST +{ + + public struct FlattenerState { + public readonly int Polarity; + public readonly bool InTerm; + + public static FlattenerState INITIAL = new FlattenerState(1, false); + + public FlattenerState(int polarity, bool inTerm) { + Polarity = polarity; + InTerm = inTerm; + } + + public FlattenerState TogglePolarity { get { + return new FlattenerState(-Polarity, InTerm); + } } + + public FlattenerState ZeroPolarity { get { + return new FlattenerState(0, InTerm); + } } + + public FlattenerState EnterTerm { get { + return new FlattenerState(Polarity, true); + } } + } + + ////////////////////////////////////////////////////////////////////////////// + + public class TermFormulaFlattener : MutatingVCExprVisitor { + + public TermFormulaFlattener(VCExpressionGenerator! gen) { + base(gen); + } + + private readonly IDictionary! Bindings = + new Dictionary (); + + private int varNameCounter = 0; + + public VCExpr! Flatten(VCExpr! expr) { + VCExpr! res = Mutate(expr, FlattenerState.INITIAL); + while (Bindings.Count > 0) { + List! letBindings = new List (); + foreach (KeyValuePair pair in Bindings) + letBindings.Add(Gen.LetBinding(pair.Value, pair.Key)); + Bindings.Clear(); + res = AddBindings(letBindings, res, FlattenerState.INITIAL); + } + return res; + } + + private VCExprVar! GetVarFor(VCExpr! expr) requires expr.Type.IsBool; { + VCExprVar res; + if (!Bindings.TryGetValue(expr, out res)) { + string! name = "flt" + varNameCounter; + varNameCounter = varNameCounter + 1; + res = Gen.Variable(name, Type.Bool); + Bindings.Add(expr, res); + } + return (!)res; + } + + // Remove all let-bindings from the field bindings whose rhs + // contains any of the specified variables + private List! + RemoveBindingsWithVars(List! boundVars, + List! boundTypeVars) { + + List! res = new List (); + FreeVariableCollector! coll = new FreeVariableCollector (); + + foreach (KeyValuePair pair in Bindings) { + coll.Collect(pair.Key); + if (exists{VCExprVar! var in boundVars; coll.FreeTermVars.ContainsKey(var)} || + exists{TypeVariable! var in boundTypeVars; coll.FreeTypeVars.Contains(var)}) + res.Add(Gen.LetBinding(pair.Value, pair.Key)); + coll.Reset(); + } + + foreach (VCExprLetBinding! b in res) + Bindings.Remove(b.E); + + return res; + } + + // Add bindings to a formula using an implication or + // conjunction. The bindings themselves will be flattened as well, + // which might introduce further bindings + private VCExpr! AddBindings(List! bindings, + VCExpr! body, + FlattenerState state) + requires body.Type.IsBool; { + + List! mutatedBindings = FlattenBindings(bindings, state); + VCExpr! bindingEquations = Gen.AsEquations(mutatedBindings); + switch(state.Polarity) { + case 1: + return Gen.Implies(bindingEquations, body); + case -1: + return Gen.And(bindingEquations, body); + case 0: + // also add explicit quantifiers for the bound variables + List! vars = new List (); + foreach (VCExprLetBinding! binding in mutatedBindings) + vars.Add(binding.V); + return Gen.Forall(vars, new List(), + Gen.Implies(bindingEquations, body)); + } + assert false; + } + + private List! FlattenBindings(List! bindings, + FlattenerState state) { + FlattenerState stateInBindings = state.ZeroPolarity; + List! mutatedBindings = new List (); + foreach (VCExprLetBinding! b in bindings) + mutatedBindings.Add(Gen.LetBinding(b.V, Mutate(b.E, stateInBindings))); + return mutatedBindings; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprNAry! node, FlattenerState state) { + // track the polarity to know whether implications or conjunctions + // are to be introduced + + if (node.Op.Equals(VCExpressionGenerator.NotOp)) + return Gen.Not(Mutate(node[0], state.TogglePolarity)); + + if (node.Op.Equals(VCExpressionGenerator.ImpliesOp)) { + VCExpr! newArg0 = Mutate(node[0], state.TogglePolarity); + VCExpr! newArg1 = Mutate(node[1], state); + return Gen.Implies(newArg0, newArg1); + } + + if (!node.Type.IsBool) + state = state.EnterTerm; + + if (!node.Op.Equals(VCExpressionGenerator.AndOp) && + !node.Op.Equals(VCExpressionGenerator.OrOp) && + !(node.Op is VCExprLabelOp)) + // standard is to set the polarity to 0 (fits most operators) + return base.Visit(node, state.ZeroPolarity); + + return base.Visit(node, state); + } + + public override VCExpr! Visit(VCExprQuantifier! node, FlattenerState state) { + if (state.InTerm) + return GetVarFor(node); + + // we only flatten within the matrix of the quantified formula, + // not within the triggers (since SMT-solvers do not seem to + // appreciate triggers with let-binders) + VCExpr! newBody = Mutate(node.Body, state); + + // Check whether any of the extracted terms contain variables + // bound by this quantifier. In this case, we have to add + // let-binders and remove the extracted terms + bool cont = true; + while (cont) { + List! localBindings = + RemoveBindingsWithVars(node.BoundVars, node.TypeParameters); + if (localBindings.Count > 0) + newBody = AddBindings(localBindings, newBody, state); + else + cont = false; + } + + return Gen.Quantify(node.Quan, node.TypeParameters, + node.BoundVars, node.Triggers, + node.Infos, newBody); + } + + public override VCExpr! Visit(VCExprLet! node, FlattenerState state) { + if (state.InTerm) + return GetVarFor(node); + + VCExprLet! prelimRes = (VCExprLet!)base.Visit(node, state); + + List! allBindings = new List (); + allBindings.AddRange(prelimRes); + + // Check whether any of the extracted terms contain variables + // bound by this binder. In this case, we have to add + // let-binders and remove the extracted terms + bool cont = true; + while (cont) { + List! localBindings = + RemoveBindingsWithVars(prelimRes.BoundVars, new List ()); + if (localBindings.Count > 0) + allBindings.AddRange(FlattenBindings(localBindings, state)); + else + cont = false; + } + + return Gen.Let(allBindings, prelimRes.Body); + } + + } + +} \ No newline at end of file diff --git a/Source/VCExpr/TermFormulaFlattening.ssc b/Source/VCExpr/TermFormulaFlattening.ssc deleted file mode 100644 index bfb8cb3a..00000000 --- a/Source/VCExpr/TermFormulaFlattening.ssc +++ /dev/null @@ -1,222 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// Ensure that no formulas (expressions of type boolean that are not -// just a variable) occur with terms (expressions of some other -// type). This is done by introducing let-binders for boolean -// variables. - -namespace Microsoft.Boogie.VCExprAST -{ - - public struct FlattenerState { - public readonly int Polarity; - public readonly bool InTerm; - - public static FlattenerState INITIAL = new FlattenerState(1, false); - - public FlattenerState(int polarity, bool inTerm) { - Polarity = polarity; - InTerm = inTerm; - } - - public FlattenerState TogglePolarity { get { - return new FlattenerState(-Polarity, InTerm); - } } - - public FlattenerState ZeroPolarity { get { - return new FlattenerState(0, InTerm); - } } - - public FlattenerState EnterTerm { get { - return new FlattenerState(Polarity, true); - } } - } - - ////////////////////////////////////////////////////////////////////////////// - - public class TermFormulaFlattener : MutatingVCExprVisitor { - - public TermFormulaFlattener(VCExpressionGenerator! gen) { - base(gen); - } - - private readonly IDictionary! Bindings = - new Dictionary (); - - private int varNameCounter = 0; - - public VCExpr! Flatten(VCExpr! expr) { - VCExpr! res = Mutate(expr, FlattenerState.INITIAL); - while (Bindings.Count > 0) { - List! letBindings = new List (); - foreach (KeyValuePair pair in Bindings) - letBindings.Add(Gen.LetBinding(pair.Value, pair.Key)); - Bindings.Clear(); - res = AddBindings(letBindings, res, FlattenerState.INITIAL); - } - return res; - } - - private VCExprVar! GetVarFor(VCExpr! expr) requires expr.Type.IsBool; { - VCExprVar res; - if (!Bindings.TryGetValue(expr, out res)) { - string! name = "flt" + varNameCounter; - varNameCounter = varNameCounter + 1; - res = Gen.Variable(name, Type.Bool); - Bindings.Add(expr, res); - } - return (!)res; - } - - // Remove all let-bindings from the field bindings whose rhs - // contains any of the specified variables - private List! - RemoveBindingsWithVars(List! boundVars, - List! boundTypeVars) { - - List! res = new List (); - FreeVariableCollector! coll = new FreeVariableCollector (); - - foreach (KeyValuePair pair in Bindings) { - coll.Collect(pair.Key); - if (exists{VCExprVar! var in boundVars; coll.FreeTermVars.ContainsKey(var)} || - exists{TypeVariable! var in boundTypeVars; coll.FreeTypeVars.Contains(var)}) - res.Add(Gen.LetBinding(pair.Value, pair.Key)); - coll.Reset(); - } - - foreach (VCExprLetBinding! b in res) - Bindings.Remove(b.E); - - return res; - } - - // Add bindings to a formula using an implication or - // conjunction. The bindings themselves will be flattened as well, - // which might introduce further bindings - private VCExpr! AddBindings(List! bindings, - VCExpr! body, - FlattenerState state) - requires body.Type.IsBool; { - - List! mutatedBindings = FlattenBindings(bindings, state); - VCExpr! bindingEquations = Gen.AsEquations(mutatedBindings); - switch(state.Polarity) { - case 1: - return Gen.Implies(bindingEquations, body); - case -1: - return Gen.And(bindingEquations, body); - case 0: - // also add explicit quantifiers for the bound variables - List! vars = new List (); - foreach (VCExprLetBinding! binding in mutatedBindings) - vars.Add(binding.V); - return Gen.Forall(vars, new List(), - Gen.Implies(bindingEquations, body)); - } - assert false; - } - - private List! FlattenBindings(List! bindings, - FlattenerState state) { - FlattenerState stateInBindings = state.ZeroPolarity; - List! mutatedBindings = new List (); - foreach (VCExprLetBinding! b in bindings) - mutatedBindings.Add(Gen.LetBinding(b.V, Mutate(b.E, stateInBindings))); - return mutatedBindings; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprNAry! node, FlattenerState state) { - // track the polarity to know whether implications or conjunctions - // are to be introduced - - if (node.Op.Equals(VCExpressionGenerator.NotOp)) - return Gen.Not(Mutate(node[0], state.TogglePolarity)); - - if (node.Op.Equals(VCExpressionGenerator.ImpliesOp)) { - VCExpr! newArg0 = Mutate(node[0], state.TogglePolarity); - VCExpr! newArg1 = Mutate(node[1], state); - return Gen.Implies(newArg0, newArg1); - } - - if (!node.Type.IsBool) - state = state.EnterTerm; - - if (!node.Op.Equals(VCExpressionGenerator.AndOp) && - !node.Op.Equals(VCExpressionGenerator.OrOp) && - !(node.Op is VCExprLabelOp)) - // standard is to set the polarity to 0 (fits most operators) - return base.Visit(node, state.ZeroPolarity); - - return base.Visit(node, state); - } - - public override VCExpr! Visit(VCExprQuantifier! node, FlattenerState state) { - if (state.InTerm) - return GetVarFor(node); - - // we only flatten within the matrix of the quantified formula, - // not within the triggers (since SMT-solvers do not seem to - // appreciate triggers with let-binders) - VCExpr! newBody = Mutate(node.Body, state); - - // Check whether any of the extracted terms contain variables - // bound by this quantifier. In this case, we have to add - // let-binders and remove the extracted terms - bool cont = true; - while (cont) { - List! localBindings = - RemoveBindingsWithVars(node.BoundVars, node.TypeParameters); - if (localBindings.Count > 0) - newBody = AddBindings(localBindings, newBody, state); - else - cont = false; - } - - return Gen.Quantify(node.Quan, node.TypeParameters, - node.BoundVars, node.Triggers, - node.Infos, newBody); - } - - public override VCExpr! Visit(VCExprLet! node, FlattenerState state) { - if (state.InTerm) - return GetVarFor(node); - - VCExprLet! prelimRes = (VCExprLet!)base.Visit(node, state); - - List! allBindings = new List (); - allBindings.AddRange(prelimRes); - - // Check whether any of the extracted terms contain variables - // bound by this binder. In this case, we have to add - // let-binders and remove the extracted terms - bool cont = true; - while (cont) { - List! localBindings = - RemoveBindingsWithVars(prelimRes.BoundVars, new List ()); - if (localBindings.Count > 0) - allBindings.AddRange(FlattenBindings(localBindings, state)); - else - cont = false; - } - - return Gen.Let(allBindings, prelimRes.Body); - } - - } - -} \ No newline at end of file diff --git a/Source/VCExpr/TypeErasure.cs b/Source/VCExpr/TypeErasure.cs new file mode 100644 index 00000000..e0852071 --- /dev/null +++ b/Source/VCExpr/TypeErasure.cs @@ -0,0 +1,1176 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// different classes for erasing complex types in VCExprs, replacing them +// with axioms that can be handled by theorem provers and SMT solvers + +namespace Microsoft.Boogie.TypeErasure +{ + using Microsoft.Boogie.VCExprAST; + + // some functionality that is needed in many places (and that should + // really be provided by the Spec# container classes; maybe one + // could integrate the functions in a nicer way?) + public class HelperFuns { + + public static Function! BoogieFunction(string! name, List! typeParams, + params Type[]! types) + requires types.Length > 0; + requires forall{int i in (0:types.Length); types[i] != null}; + { + VariableSeq! args = new VariableSeq (); + for (int i = 0; i < types.Length - 1; ++i) + args.Add(new Formal (Token.NoToken, + new TypedIdent (Token.NoToken, "arg" + i, (!)types[i]), + true)); + Formal! result = new Formal (Token.NoToken, + new TypedIdent (Token.NoToken, "res", + (!)types[types.Length - 1]), + false); + return new Function (Token.NoToken, name, ToSeq(typeParams), args, result); + } + + public static Function! BoogieFunction(string! name, params Type[]! types) { + return BoogieFunction(name, new List (), types); + } + + // boogie function where all arguments and the result have the same type U + public static Function! UniformBoogieFunction(string! name, int arity, Type! U) { + Type[]! types = new Type [arity + 1]; + for (int i = 0; i < arity + 1; ++i) + types[i] = U; + return BoogieFunction(name, types); + } + + public static List! GenVarsForInParams(Function! fun, + VCExpressionGenerator! gen) { + List! arguments = new List (fun.InParams.Length); + foreach (Formal! f in fun.InParams) { + VCExprVar! var = gen.Variable(f.Name, f.TypedIdent.Type); + arguments.Add(var); + } + return arguments; + } + + public static List! ToList (params T[]! args) { + List! res = new List (args.Length); + foreach (T t in args) + res.Add((!)t); + return res; + } + + public static List! ToList(TypeVariableSeq! seq) { + List! res = new List (seq.Length); + foreach (TypeVariable! var in seq) + res.Add(var); + return res; + } + + public static TypeVariableSeq! ToSeq(List! list) { + TypeVariableSeq! res = new TypeVariableSeq (); + foreach (TypeVariable! var in list) + res.Add(var); + return res; + } + + public static List! Intersect(List! a, List! b) { + List! res = new List (Math.Min(a.Count, b.Count)); + foreach (T x in a) + if (b.Contains(x)) + res.Add(x); + res.TrimExcess(); + return res; + } + + public static List>! ToPairList(IDictionary! dict) { + List>! res = new List> (dict); + return res; + } + + public static void AddRangeWithoutDups(IEnumerable! fromList, List! toList) { + foreach (T t in fromList) + if (!toList.Contains(t)) + toList.Add(t); + } + + public static void AddFreeVariablesWithoutDups(Type! type, List! toList) { + foreach (TypeVariable! var in type.FreeVariables) { + if (!toList.Contains(var)) + toList.Add(var); + } + } + + public static List! ToVCExprList(List! list) { + List! res = new List (list.Count); + foreach (VCExprVar! var in list) + res.Add(var); + return res; + } + + public static List! VarVector(string! baseName, int num, Type! type, + VCExpressionGenerator! gen) { + List! res = new List (num); + for (int i = 0; i < num; ++i) + res.Add(gen.Variable(baseName + i, type)); + return res; + } + + public static List! VarVector(string! baseName, List! types, + VCExpressionGenerator! gen) { + List! res = new List (types.Count); + for (int i = 0; i < types.Count; ++i) + res.Add(gen.Variable(baseName + i, types[i])); + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + internal struct TypeCtorRepr { + // function that represents the application of the type constructor + // to smaller types + public readonly Function! Ctor; + // left-inverse functions that extract the subtypes of a compound type + public readonly List! Dtors; + + public TypeCtorRepr(Function! ctor, List! dtors) + requires ctor.InParams.Length == dtors.Count; { + this.Ctor = ctor; + this.Dtors = dtors; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + // The class responsible for creating and keeping track of all + // axioms related to the type system. This abstract class is made + // concrete in two subclasses, one for type erasure with type + // premisses in quantifiers (the semantic approach), and one for + // type erasure with explicit type arguments of polymorphic + // functions (the syntacted approach). + public abstract class TypeAxiomBuilder : ICloneable { + + protected readonly VCExpressionGenerator! Gen; + + internal abstract MapTypeAbstractionBuilder! MapTypeAbstracter { get; } + + /////////////////////////////////////////////////////////////////////////// + // Type Axioms + + // list in which all typed axioms are collected + private readonly List! AllTypeAxioms; + + // list in which type axioms are incrementally collected + private readonly List! IncTypeAxioms; + + internal void AddTypeAxiom(VCExpr! axiom) { + AllTypeAxioms.Add(axiom); + IncTypeAxioms.Add(axiom); + } + + // Return all axioms that were added since the last time NewAxioms + // was called + public VCExpr! GetNewAxioms() { + VCExpr! res = Gen.NAry(VCExpressionGenerator.AndOp, IncTypeAxioms); + IncTypeAxioms.Clear(); + return res; + } + + // mapping from a type to its constructor number/index + private readonly Function! Ctor; + private BigNum CurrentCtorNum; + + private VCExpr! GenCtorAssignment(VCExpr! typeRepr) { + if (CommandLineOptions.Clo.TypeEncodingMethod + == CommandLineOptions.TypeEncoding.None) + return VCExpressionGenerator.True; + + VCExpr! res = Gen.Eq(Gen.Function(Ctor, typeRepr), + Gen.Integer(CurrentCtorNum)); + CurrentCtorNum = CurrentCtorNum + BigNum.ONE; + return res; + } + + private VCExpr! GenCtorAssignment(Function! typeRepr) { + if (CommandLineOptions.Clo.TypeEncodingMethod + == CommandLineOptions.TypeEncoding.None) + return VCExpressionGenerator.True; + + List! quantifiedVars = HelperFuns.GenVarsForInParams(typeRepr, Gen); + VCExpr! eq = + GenCtorAssignment(Gen.Function(typeRepr, + HelperFuns.ToVCExprList(quantifiedVars))); + + if (typeRepr.InParams.Length == 0) + return eq; + + return Gen.Forall(quantifiedVars, new List (), + "ctor:" + typeRepr.Name, eq); + } + + // generate an axiom (forall x0, x1, ... :: invFun(fun(x0, x1, ...) == xi) + protected VCExpr! GenLeftInverseAxiom(Function! fun, Function! invFun, int dtorNum) { + List! quantifiedVars = HelperFuns.GenVarsForInParams(fun, Gen); + + VCExpr! funApp = Gen.Function(fun, HelperFuns.ToVCExprList(quantifiedVars)); + VCExpr! lhs = Gen.Function(invFun, funApp); + VCExpr! rhs = quantifiedVars[dtorNum]; + VCExpr! eq = Gen.Eq(lhs, rhs); + + List! triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(funApp))); + return Gen.Forall(quantifiedVars, triggers, "typeInv:" + invFun.Name, eq); + } + + /////////////////////////////////////////////////////////////////////////// + + // the type of everything that is not int, bool, or a type + private readonly TypeCtorDecl! UDecl; + public readonly Type! U; + + // the type of types + private readonly TypeCtorDecl! TDecl; + public readonly Type! T; + + public abstract Type! TypeAfterErasure(Type! type); + public abstract bool UnchangedType(Type! type); + + /////////////////////////////////////////////////////////////////////////// + // Symbols for representing types + + private readonly IDictionary! BasicTypeReprs; + + private VCExpr! GetBasicTypeRepr(Type! type) + requires type.IsBasic || type.IsBv; { + VCExpr res; + if (!BasicTypeReprs.TryGetValue(type, out res)) { + res = Gen.Function(HelperFuns.BoogieFunction(type.ToString() + "Type", T)); + AddTypeAxiom(GenCtorAssignment(res)); + BasicTypeReprs.Add(type, res); + } + return (!)res; + } + + private readonly IDictionary! TypeCtorReprs; + + internal TypeCtorRepr GetTypeCtorReprStruct(TypeCtorDecl! decl) { + TypeCtorRepr reprSet; + if (!TypeCtorReprs.TryGetValue(decl, out reprSet)) { + Function! ctor = HelperFuns.UniformBoogieFunction(decl.Name + "Type", decl.Arity, T); + AddTypeAxiom(GenCtorAssignment(ctor)); + + List! dtors = new List(decl.Arity); + for (int i = 0; i < decl.Arity; ++i) { + Function! dtor = HelperFuns.UniformBoogieFunction(decl.Name + "TypeInv" + i, 1, T); + dtors.Add(dtor); + AddTypeAxiom(GenLeftInverseAxiom(ctor, dtor, i)); + } + + reprSet = new TypeCtorRepr(ctor, dtors); + TypeCtorReprs.Add(decl, reprSet); + } + + return reprSet; + } + + public Function! GetTypeCtorRepr(TypeCtorDecl! decl) { + return GetTypeCtorReprStruct(decl).Ctor; + } + + public Function! GetTypeDtor(TypeCtorDecl! decl, int num) { + return GetTypeCtorReprStruct(decl).Dtors[num]; + } + + // mapping from free type variables to VCExpr variables + private readonly IDictionary! TypeVariableMapping; + + public VCExprVar! Typed2Untyped(TypeVariable! var) { + VCExprVar res; + if (!TypeVariableMapping.TryGetValue(var, out res)) { + res = new VCExprVar (var.Name, T); + TypeVariableMapping.Add(var, res); + } + return (!)res; + } + + + //////////////////////////////////////////////////////////////////////////// + // Symbols for representing variables and constants + + // Globally defined variables + private readonly IDictionary! Typed2UntypedVariables; + + // This method must only be used for free (unbound) variables + public VCExprVar! Typed2Untyped(VCExprVar! var) { + VCExprVar res; + if (!Typed2UntypedVariables.TryGetValue(var, out res)) { + res = Gen.Variable(var.Name, TypeAfterErasure(var.Type)); + Typed2UntypedVariables.Add(var, res); + AddVarTypeAxiom(res, var.Type); + } + return (!)res; + } + + protected abstract void AddVarTypeAxiom(VCExprVar! var, Type! originalType); + + /////////////////////////////////////////////////////////////////////////// + // Translation function from types to their term representation + + public VCExpr! Type2Term(Type! type, + IDictionary! varMapping) { + // + if (type.IsBasic || type.IsBv) { + // + return GetBasicTypeRepr(type); + // + } else if (type.IsCtor) { + // + CtorType ctype = type.AsCtor; + Function! repr = GetTypeCtorRepr(ctype.Decl); + List! args = new List (ctype.Arguments.Length); + foreach (Type! t in ctype.Arguments) + args.Add(Type2Term(t, varMapping)); + return Gen.Function(repr, args); + // + } else if (type.IsVariable) { + // + VCExpr res; + if (!varMapping.TryGetValue(type.AsVariable, out res)) + // then the variable is free and we bind it at this point to a term + // variable + res = Typed2Untyped(type.AsVariable); + return (!)res; + // + } else if (type.IsMap) { + // + return Type2Term(MapTypeAbstracter.AbstractMapType(type.AsMap), varMapping); + // + } else { + System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + type); + assert false; // please the compiler + } + } + + //////////////////////////////////////////////////////////////////////////// + + public TypeAxiomBuilder(VCExpressionGenerator! gen) { + this.Gen = gen; + AllTypeAxioms = new List (); + IncTypeAxioms = new List (); + BasicTypeReprs = new Dictionary (); + CurrentCtorNum = BigNum.ZERO; + TypeCtorReprs = new Dictionary (); + TypeVariableMapping = new Dictionary (); + Typed2UntypedVariables = new Dictionary (); + + TypeCtorDecl! uDecl = new TypeCtorDecl(Token.NoToken, "U", 0); + UDecl = uDecl; + Type! u = new CtorType (Token.NoToken, uDecl, new TypeSeq ()); + U = u; + + TypeCtorDecl! tDecl = new TypeCtorDecl(Token.NoToken, "T", 0); + TDecl = tDecl; + Type! t = new CtorType (Token.NoToken, tDecl, new TypeSeq ()); + T = t; + + Ctor = HelperFuns.BoogieFunction("Ctor", t, Type.Int); + } + + public virtual void Setup() { + GetBasicTypeRepr(Type.Int); + GetBasicTypeRepr(Type.Bool); + } + + // constructor to allow cloning + internal TypeAxiomBuilder(TypeAxiomBuilder! builder) { + Gen = builder.Gen; + AllTypeAxioms = new List (builder.AllTypeAxioms); + IncTypeAxioms = new List (builder.IncTypeAxioms); + + UDecl = builder.UDecl; + U = builder.U; + + TDecl = builder.TDecl; + T = builder.T; + + Ctor = builder.Ctor; + CurrentCtorNum = builder.CurrentCtorNum; + + BasicTypeReprs = new Dictionary (builder.BasicTypeReprs); + TypeCtorReprs = new Dictionary (builder.TypeCtorReprs); + + TypeVariableMapping = + new Dictionary (builder.TypeVariableMapping); + Typed2UntypedVariables = + new Dictionary (builder.Typed2UntypedVariables); + } + + public abstract Object! Clone(); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Subclass of the TypeAxiomBuilder that provides all functionality + // to deal with native sorts of a theorem prover (that are the only + // types left after erasing all other types). Currently, these are: + // + // U ... sort of all individuals/objects/values + // T ... sort of all types + // int ... integers + // bool ... booleans + + public abstract class TypeAxiomBuilderIntBoolU : TypeAxiomBuilder { + + public TypeAxiomBuilderIntBoolU(VCExpressionGenerator! gen) { + base(gen); + TypeCasts = new Dictionary (); + } + + // constructor to allow cloning + internal TypeAxiomBuilderIntBoolU(TypeAxiomBuilderIntBoolU! builder) { + base(builder); + TypeCasts = new Dictionary (builder.TypeCasts); + } + + public override void Setup() { + base.Setup(); + + GetTypeCasts(Type.Int); + GetTypeCasts(Type.Bool); + } + + // generate inverse axioms for casts (castToU(castFromU(x)) = x, under certain premisses) + protected abstract VCExpr! GenReverseCastAxiom(Function! castToU, Function! castFromU); + + protected VCExpr! GenReverseCastEq(Function! castToU, Function! castFromU, + out VCExprVar! var, out List! triggers) { + var = Gen.Variable("x", U); + + VCExpr inner = Gen.Function(castFromU, var); + VCExpr lhs = Gen.Function(castToU, inner); + triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(inner))); + + return Gen.Eq(lhs, var); + } + + protected abstract VCExpr! GenCastTypeAxioms(Function! castToU, Function! castFromU); + + /////////////////////////////////////////////////////////////////////////// + // storage of type casts for types that are supposed to be left over in the + // VCs (like int, bool, bitvectors) + + private readonly IDictionary! TypeCasts; + + private TypeCastSet GetTypeCasts(Type! type) { + TypeCastSet res; + if (!TypeCasts.TryGetValue(type, out res)) { + Function! castToU = HelperFuns.BoogieFunction(type.ToString() + "_2_U", type, U); + Function! castFromU = HelperFuns.BoogieFunction("U_2_" + type.ToString(), U, type); + + AddTypeAxiom(GenLeftInverseAxiom(castToU, castFromU, 0)); + AddTypeAxiom(GenReverseCastAxiom(castToU, castFromU)); + AddTypeAxiom(GenCastTypeAxioms(castToU, castFromU)); + + res = new TypeCastSet (castToU, castFromU); + TypeCasts.Add(type, res); + } + return res; + } + + public Function! CastTo(Type! type) + requires UnchangedType(type); { + return GetTypeCasts(type).CastFromU; + } + + public Function! CastFrom(Type! type) + requires UnchangedType(type); { + return GetTypeCasts(type).CastToU; + } + + private struct TypeCastSet { + public readonly Function! CastToU; + public readonly Function! CastFromU; + + public TypeCastSet(Function! castToU, Function! castFromU) { + CastToU = castToU; + CastFromU = castFromU; + } + } + + public bool IsCast(Function! fun) { + if (fun.InParams.Length != 1) + return false; + Type! inType = ((!)fun.InParams[0]).TypedIdent.Type; + if (inType.Equals(U)) { + Type! outType = ((!)fun.OutParams[0]).TypedIdent.Type; + if (!TypeCasts.ContainsKey(outType)) + return false; + return fun.Equals(CastTo(outType)); + } else { + if (!TypeCasts.ContainsKey(inType)) + return false; + Type! outType = ((!)fun.OutParams[0]).TypedIdent.Type; + if (!outType.Equals(U)) + return false; + return fun.Equals(CastFrom(inType)); + } + } + + //////////////////////////////////////////////////////////////////////////// + + // the only types that we allow in "untyped" expressions are U, + // Type.Int, and Type.Bool + + public override Type! TypeAfterErasure(Type! type) { + if (UnchangedType(type)) + // these types are kept + return type; + else + // all other types are replaced by U + return U; + } + + [Pure] + public override bool UnchangedType(Type! type) { + return type.IsInt || type.IsBool || type.IsBv || (type.IsMap && CommandLineOptions.Clo.UseArrayTheory); + } + + public VCExpr! Cast(VCExpr! expr, Type! toType) + requires expr.Type.Equals(U) || UnchangedType(expr.Type); + requires toType.Equals(U) || UnchangedType(toType); + { + if (expr.Type.Equals(toType)) + return expr; + + if (toType.Equals(U)) { + return Gen.Function(CastFrom(expr.Type), expr); + } else { + assert expr.Type.Equals(U); + return Gen.Function(CastTo(toType), expr); + } + } + + public List! CastSeq(List! exprs, Type! toType) { + List! res = new List (exprs.Count); + foreach (VCExpr! expr in exprs) + res.Add(Cast(expr, toType)); + return res; + } + + + } + + ////////////////////////////////////////////////////////////////////////////// + // Class for computing most general abstractions of map types. An abstraction + // of a map type t is a maptype t' in which closed proper subtypes have been replaced + // with type variables. E.g., an abstraction of [C a, int]a would be [C a, b]a. + // We subsequently consider most general abstractions as ordinary parametrised types, + // i.e., "[C a, b]a" would be considered as a type "M b" with polymorphically typed + // access functions + // + // select(M b, C a, b) returns (a) + // store(M b, C a, b, a) returns (M b) + + internal abstract class MapTypeAbstractionBuilder { + + protected readonly TypeAxiomBuilder! AxBuilder; + protected readonly VCExpressionGenerator! Gen; + + internal MapTypeAbstractionBuilder(TypeAxiomBuilder! axBuilder, + VCExpressionGenerator! gen) { + this.AxBuilder = axBuilder; + this.Gen = gen; + AbstractionVariables = new List (); + ClassRepresentations = new Dictionary (); + } + + // constructor for cloning + internal MapTypeAbstractionBuilder(TypeAxiomBuilder! axBuilder, + VCExpressionGenerator! gen, + MapTypeAbstractionBuilder! builder) { + this.AxBuilder = axBuilder; + this.Gen = gen; + AbstractionVariables = + new List (builder.AbstractionVariables); + ClassRepresentations = + new Dictionary (builder.ClassRepresentations); + } + + /////////////////////////////////////////////////////////////////////////// + // Type variables used in the abstractions. We use the same variables in the + // same order in all abstractions in order to obtain comparable abstractions + // (equals, hashcode) + + private readonly List! AbstractionVariables; + + private TypeVariable! AbstractionVariable(int num) + requires num >= 0; { + while (AbstractionVariables.Count <= num) + AbstractionVariables.Add(new TypeVariable (Token.NoToken, + "aVar" + AbstractionVariables.Count)); + return AbstractionVariables[num]; + } + + /////////////////////////////////////////////////////////////////////////// + // The untyped representation of a class of map types, i.e., of a map type + // [A0, A1, ...] R, where the argument types and the result type + // possibly contain free type variables. For each such class, a separate type + // constructor and separate select/store functions are introduced. + + protected struct MapTypeClassRepresentation { + public readonly TypeCtorDecl! RepresentingType; + public readonly Function! Select; + public readonly Function! Store; + + public MapTypeClassRepresentation(TypeCtorDecl! representingType, + Function! select, Function! store) { + this.RepresentingType = representingType; + this.Select = select; + this.Store = store; + } + } + + private readonly IDictionary! ClassRepresentations; + + protected MapTypeClassRepresentation GetClassRepresentation(MapType! abstractedType) { + MapTypeClassRepresentation res; + if (!ClassRepresentations.TryGetValue(abstractedType, out res)) { + int num = ClassRepresentations.Count; + TypeCtorDecl! synonym = + new TypeCtorDecl(Token.NoToken, "MapType" + num, abstractedType.FreeVariables.Length); + + Function! select, store; + GenSelectStoreFunctions(abstractedType, synonym, out select, out store); + + res = new MapTypeClassRepresentation(synonym, select, store); + ClassRepresentations.Add(abstractedType, res); + } + return res; + } + + // the actual select and store functions are generated by the + // concrete subclasses of this class + protected abstract void GenSelectStoreFunctions(MapType! abstractedType, + TypeCtorDecl! synonymDecl, + out Function! select, out Function! store); + + /////////////////////////////////////////////////////////////////////////// + + public Function! Select(MapType! rawType, out TypeSeq! instantiations) { + return AbstractAndGetRepresentation(rawType, out instantiations).Select; + } + + public Function! Store(MapType! rawType, out TypeSeq! instantiations) { + return AbstractAndGetRepresentation(rawType, out instantiations).Store; + } + + private MapTypeClassRepresentation + AbstractAndGetRepresentation(MapType! rawType, out TypeSeq! instantiations) { + instantiations = new TypeSeq (); + MapType! abstraction = ThinOutMapType(rawType, instantiations); + return GetClassRepresentation(abstraction); + } + + public CtorType! AbstractMapType(MapType! rawType) { + TypeSeq! instantiations = new TypeSeq (); + MapType! abstraction = ThinOutMapType(rawType, instantiations); + + MapTypeClassRepresentation repr = GetClassRepresentation(abstraction); + assume repr.RepresentingType.Arity == instantiations.Length; + return new CtorType(Token.NoToken, repr.RepresentingType, instantiations); + } + + // TODO: cache the result of this operation + protected MapType! ThinOutMapType(MapType! rawType, + TypeSeq! instantiations) { + TypeSeq! newArguments = new TypeSeq (); + foreach (Type! subtype in rawType.Arguments) + newArguments.Add(ThinOutType(subtype, rawType.TypeParameters, + instantiations)); + Type! newResult = ThinOutType(rawType.Result, rawType.TypeParameters, + instantiations); + return new MapType(Token.NoToken, rawType.TypeParameters, newArguments, newResult); + } + + private Type! ThinOutType(Type! rawType, TypeVariableSeq! boundTypeParams, + // the instantiations of inserted type variables, + // the order corresponds to the order in which + // "AbstractionVariable(int)" delivers variables + TypeSeq! instantiations) { + + if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(rawType)) + return rawType; + + if (forall{TypeVariable! var in rawType.FreeVariables; + !boundTypeParams.Has(var)}) { + // Bingo! + // if the type does not contain any bound variables, we can simply + // replace it with a type variable + TypeVariable! abstractionVar = AbstractionVariable(instantiations.Length); + assume !boundTypeParams.Has(abstractionVar); + instantiations.Add(rawType); + return abstractionVar; + } + + if (rawType.IsVariable) { + // + // then the variable has to be bound, we cannot do anything + TypeVariable! rawVar = rawType.AsVariable; + assume boundTypeParams.Has(rawVar); + return rawVar; + // + } else if (rawType.IsMap) { + // + // recursively abstract this map type and continue abstracting + CtorType! abstraction = AbstractMapType(rawType.AsMap); + return ThinOutType(abstraction, boundTypeParams, instantiations); + // + } else if (rawType.IsCtor) { + // + // traverse the subtypes + CtorType! rawCtorType = rawType.AsCtor; + TypeSeq! newArguments = new TypeSeq (); + foreach (Type! subtype in rawCtorType.Arguments) + newArguments.Add(ThinOutType(subtype, boundTypeParams, + instantiations)); + return new CtorType(Token.NoToken, rawCtorType.Decl, newArguments); + // + } else { + System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + rawType); + return rawType; // compiler appeasement policy + } + } + + } + + ////////////////////////////////////////////////////////////////////////////// + + public class VariableBindings { + public readonly IDictionary! VCExprVarBindings; + public readonly IDictionary! TypeVariableBindings; + + public VariableBindings(IDictionary! vcExprVarBindings, + IDictionary! typeVariableBindings) { + this.VCExprVarBindings = vcExprVarBindings; + this.TypeVariableBindings = typeVariableBindings; + } + + public VariableBindings() { + this (new Dictionary (), + new Dictionary ()); + } + + public VariableBindings! Clone() { + IDictionary! newVCExprVarBindings = + new Dictionary (); + foreach (KeyValuePair pair in VCExprVarBindings) + newVCExprVarBindings.Add(pair); + IDictionary! newTypeVariableBindings = + new Dictionary (); + foreach (KeyValuePair pair in TypeVariableBindings) + newTypeVariableBindings.Add(pair); + return new VariableBindings(newVCExprVarBindings, newTypeVariableBindings); + } + } + + ////////////////////////////////////////////////////////////////////////////// + + // The central class for turning types VCExprs into untyped + // VCExprs. This class makes use of the type axiom builder to manage + // the available types and symbols. + + public abstract class TypeEraser : MutatingVCExprVisitor { + + protected readonly TypeAxiomBuilderIntBoolU! AxBuilder; + + protected abstract OpTypeEraser! OpEraser { get; } + + //////////////////////////////////////////////////////////////////////////// + + public TypeEraser(TypeAxiomBuilderIntBoolU! axBuilder, VCExpressionGenerator! gen) { + base(gen); + AxBuilder = axBuilder; + } + + public VCExpr! Erase(VCExpr! expr, int polarity) + requires polarity >= -1 && polarity <= 1; { + this.Polarity = polarity; + return Mutate(expr, new VariableBindings()); + } + + internal int Polarity = 1; // 1 for positive, -1 for negative, 0 for both + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprLiteral! node, VariableBindings! bindings) { + assume node.Type == Type.Bool || node.Type == Type.Int; + return node; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprNAry! node, VariableBindings! bindings) { + VCExprOp! op = node.Op; + if (op == VCExpressionGenerator.AndOp || op == VCExpressionGenerator.OrOp) + // more efficient on large conjunctions/disjunctions + return base.Visit(node, bindings); + + // the visitor that handles all other operators + return node.Accept(OpEraser, bindings); + } + + // this method is called by MutatingVCExprVisitor.Visit(VCExprNAry, ...) + protected override VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, + List! newSubExprs, + bool changed, + VariableBindings! bindings) { + assume originalNode.Op == VCExpressionGenerator.AndOp || + originalNode.Op == VCExpressionGenerator.OrOp; + return Gen.Function(originalNode.Op, + AxBuilder.Cast(newSubExprs[0], Type.Bool), + AxBuilder.Cast(newSubExprs[1], Type.Bool)); + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprVar! node, VariableBindings! bindings) { + VCExprVar res; + if (!bindings.VCExprVarBindings.TryGetValue(node, out res)) + return AxBuilder.Typed2Untyped(node); + return (!)res; + } + + //////////////////////////////////////////////////////////////////////////// + + protected bool IsUniversalQuantifier(VCExprQuantifier! node) { + return Polarity == 1 && node.Quan == Quantifier.EX || + Polarity == -1 && node.Quan == Quantifier.ALL; + } + + protected List! BoundVarsAfterErasure(List! oldBoundVars, + // the mapping between old and new variables + // is added to this bindings-object + VariableBindings! bindings) { + List! newBoundVars = new List (oldBoundVars.Count); + foreach (VCExprVar! var in oldBoundVars) { + Type! newType = AxBuilder.TypeAfterErasure(var.Type); + VCExprVar! newVar = Gen.Variable(var.Name, newType); + newBoundVars.Add(newVar); + bindings.VCExprVarBindings.Add(var, newVar); + } + return newBoundVars; + } + + // We check whether casts Int2U or Bool2U on the bound variables + // occur in triggers. In case a trigger like f(Int2U(x)) occurs, + // it may be better to give variable x the type U and remove the + // cast. The following method returns true if the quantifier + // should be translated again with a different typing + protected bool RedoQuantifier(VCExprQuantifier! node, + VCExprQuantifier! newNode, + // the bound vars that actually occur in the body or + // in any of the triggers + List! occurringVars, + VariableBindings! oldBindings, + out VariableBindings! newBindings, + out List! newBoundVars) { + List castVariables = + VariableCastCollector.FindCastVariables(node, newNode, AxBuilder); + if (castVariables.Count == 0) { + newBindings = oldBindings; // to make the compiler happy + newBoundVars = newNode.BoundVars; // to make the compiler happy + return false; + } + + // redo everything with a different typing ... + + newBindings = oldBindings.Clone(); + newBoundVars = new List (node.BoundVars.Count); + foreach (VCExprVar! var in node.BoundVars) { + Type! newType = + castVariables.Contains(var) ? AxBuilder.U + : AxBuilder.TypeAfterErasure(var.Type); + VCExprVar! newVar = Gen.Variable(var.Name, newType); + newBoundVars.Add(newVar); + newBindings.VCExprVarBindings.Add(var, newVar); + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprLet! node, VariableBindings! bindings) { + VariableBindings! newVarBindings = bindings.Clone(); + + List! newBoundVars = new List (node.BoundVars.Count); + foreach (VCExprVar! var in node.BoundVars) { + Type! newType = AxBuilder.TypeAfterErasure(var.Type); + VCExprVar! newVar = Gen.Variable(var.Name, newType); + newBoundVars.Add(newVar); + newVarBindings.VCExprVarBindings.Add(var, newVar); + } + + List! newbindings = new List (node.Length); + for (int i = 0; i < node.Length; ++i) { + VCExprLetBinding! binding = node[i]; + VCExprVar! newVar = newBoundVars[i]; + Type! newType = newVar.Type; + + VCExpr! newE = AxBuilder.Cast(Mutate(binding.E, newVarBindings), newType); + newbindings.Add(Gen.LetBinding(newVar, newE)); + } + + VCExpr! newbody = Mutate(node.Body, newVarBindings); + return Gen.Let(newbindings, newbody); + } + } + + ////////////////////////////////////////////////////////////////////////////// + + public abstract class OpTypeEraser : StandardVCExprOpVisitor { + + protected readonly TypeAxiomBuilderIntBoolU! AxBuilder; + + protected readonly TypeEraser! Eraser; + protected readonly VCExpressionGenerator! Gen; + + public OpTypeEraser(TypeEraser! eraser, TypeAxiomBuilderIntBoolU! axBuilder, + VCExpressionGenerator! gen) { + this.AxBuilder = axBuilder; + this.Eraser = eraser; + this.Gen = gen; + } + + protected override VCExpr! StandardResult(VCExprNAry! node, VariableBindings! bindings) { + System.Diagnostics.Debug.Fail("Don't know how to erase types in this expression: " + node); + assert false; // to please the compiler + } + + private List! MutateSeq(VCExprNAry! node, VariableBindings! bindings, + int newPolarity) { + int oldPolarity = Eraser.Polarity; + Eraser.Polarity = newPolarity; + List! newArgs = Eraser.MutateSeq(node, bindings); + Eraser.Polarity = oldPolarity; + return newArgs; + } + + private VCExpr! CastArguments(VCExprNAry! node, Type! argType, VariableBindings! bindings, + int newPolarity) { + return Gen.Function(node.Op, + AxBuilder.CastSeq(MutateSeq(node, bindings, newPolarity), + argType)); + } + + // Cast the arguments of the node to their old type if necessary and possible; otherwise use + // their new type (int, bool, or U) + private VCExpr! CastArgumentsToOldType(VCExprNAry! node, VariableBindings! bindings, + int newPolarity) + requires node.Arity > 0; { + + List! newArgs = MutateSeq(node, bindings, newPolarity); + Type! oldType = node[0].Type; + if (AxBuilder.UnchangedType(oldType) && + forall{int i in (1:node.Arity); node[i].Type.Equals(oldType)}) + return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, oldType)); + else + return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, AxBuilder.U)); + } + + /////////////////////////////////////////////////////////////////////////// + + public override VCExpr! VisitNotOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Bool, bindings, -Eraser.Polarity); + } + public override VCExpr! VisitEqOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr! VisitNeqOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr! VisitImpliesOp (VCExprNAry! node, VariableBindings! bindings) { + // UGLY: the code for tracking polarities should be factored out + List! newArgs = new List (2); + Eraser.Polarity = -Eraser.Polarity; + newArgs.Add(Eraser.Mutate(node[0], bindings)); + Eraser.Polarity = -Eraser.Polarity; + newArgs.Add(Eraser.Mutate(node[1], bindings)); + return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, Type.Bool)); + } + public override VCExpr! VisitDistinctOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr! VisitLabelOp (VCExprNAry! node, VariableBindings! bindings) { + // argument of the label operator should always be a formula + // (at least for Simplify ... should this be ensured at a later point?) + return CastArguments(node, Type.Bool, bindings, Eraser.Polarity); + } + public override VCExpr! VisitIfThenElseOp (VCExprNAry! node, VariableBindings! bindings) { + List! newArgs = MutateSeq(node, bindings, 0); + newArgs[0] = AxBuilder.Cast(newArgs[0], Type.Bool); + Type t = node.Type; + if (!AxBuilder.UnchangedType(t)) { + t = AxBuilder.U; + } + newArgs[1] = AxBuilder.Cast(newArgs[1], t); + newArgs[2] = AxBuilder.Cast(newArgs[2], t); + return Gen.Function(node.Op, newArgs); + } + public override VCExpr! VisitCustomOp (VCExprNAry! node, VariableBindings! bindings) { + List! newArgs = MutateSeq(node, bindings, 0); + return Gen.Function(node.Op, newArgs); + } + public override VCExpr! VisitAddOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitSubOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitMulOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitDivOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitModOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitLtOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitLeOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitGtOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitGeOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, Type.Int, bindings, 0); + } + public override VCExpr! VisitSubtypeOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArguments(node, AxBuilder.U, bindings, 0); + } + public override VCExpr! VisitBvOp (VCExprNAry! node, VariableBindings! bindings) { + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr! VisitBvExtractOp(VCExprNAry! node, VariableBindings! bindings) { + return CastArgumentsToOldType(node, bindings, 0); + } + public override VCExpr! VisitBvConcatOp (VCExprNAry! node, VariableBindings! bindings) { + List! newArgs = MutateSeq(node, bindings, 0); + + // each argument is cast to its old type + assert newArgs.Count == node.Arity && newArgs.Count == 2; + VCExpr! arg0 = AxBuilder.Cast(newArgs[0], node[0].Type); + VCExpr! arg1 = AxBuilder.Cast(newArgs[1], node[1].Type); + + return Gen.Function(node.Op, arg0, arg1); + } + + } + + ////////////////////////////////////////////////////////////////////////////// + + /// + /// Collect all variables x occurring in expressions of the form Int2U(x) or Bool2U(x), and + /// collect all variables x occurring outside such forms. + /// + internal class VariableCastCollector : TraversingVCExprVisitor { + /// + /// Determine those bound variables in "oldNode" all of whose relevant uses + /// have to be cast in potential triggers in "newNode". It is assume that + /// the bound variables of "oldNode" correspond to the first bound + /// variables of "newNode". + /// + public static List! FindCastVariables(VCExprQuantifier! oldNode, + VCExprQuantifier! newNode, + TypeAxiomBuilderIntBoolU! axBuilder) { + VariableCastCollector! collector = new VariableCastCollector(axBuilder); + if (exists{VCTrigger! trigger in newNode.Triggers; trigger.Pos}) { + // look in the given triggers + foreach (VCTrigger! trigger in newNode.Triggers) + if (trigger.Pos) + foreach (VCExpr! expr in trigger.Exprs) + collector.Traverse(expr, true); + } else { + // look in the body of the quantifier + collector.Traverse(newNode.Body, true); + } + + List! castVariables = new List (collector.varsInCasts.Count); + foreach (VCExprVar! castVar in collector.varsInCasts) { + int i = newNode.BoundVars.IndexOf(castVar); + if (0 <= i && i < oldNode.BoundVars.Count && !collector.varsOutsideCasts.ContainsKey(castVar)) + castVariables.Add(oldNode.BoundVars[i]); + } + return castVariables; + } + + public VariableCastCollector(TypeAxiomBuilderIntBoolU! axBuilder) { + this.AxBuilder = axBuilder; + } + + readonly List! varsInCasts = new List (); + readonly Dictionary! varsOutsideCasts = new Dictionary (); + + readonly TypeAxiomBuilderIntBoolU! AxBuilder; + + protected override bool StandardResult(VCExpr! node, bool arg) { + return true; // not used + } + + public override bool Visit(VCExprNAry! node, bool arg) { + if (node.Op is VCExprBoogieFunctionOp) { + Function! func = ((VCExprBoogieFunctionOp)node.Op).Func; + if ((AxBuilder.IsCast(func)) && node[0] is VCExprVar) { + VCExprVar castVar = (VCExprVar)node[0]; + if (!varsInCasts.Contains(castVar)) + varsInCasts.Add(castVar); + return true; + } + } else if (node.Op is VCExprNAryOp) { + VCExpressionGenerator.SingletonOp op = VCExpressionGenerator.SingletonOpDict[node.Op]; + switch(op) { + // the following operators cannot be used in triggers, so disregard any uses of variables as direct arguments + case VCExpressionGenerator.SingletonOp.NotOp: + case VCExpressionGenerator.SingletonOp.EqOp: + case VCExpressionGenerator.SingletonOp.NeqOp: + case VCExpressionGenerator.SingletonOp.AndOp: + case VCExpressionGenerator.SingletonOp.OrOp: + case VCExpressionGenerator.SingletonOp.ImpliesOp: + case VCExpressionGenerator.SingletonOp.LtOp: + case VCExpressionGenerator.SingletonOp.LeOp: + case VCExpressionGenerator.SingletonOp.GtOp: + case VCExpressionGenerator.SingletonOp.GeOp: + foreach (VCExpr n in node) { + if (!(n is VCExprVar)) { // don't recurse on VCExprVar argument + n.Accept(this, arg); + } + } + return true; + default: + break; + } + } + return base.Visit(node, arg); + } + + public override bool Visit(VCExprVar! node, bool arg) { + if (!varsOutsideCasts.ContainsKey(node)) + varsOutsideCasts.Add(node, null); + return true; + } + } + +} diff --git a/Source/VCExpr/TypeErasure.ssc b/Source/VCExpr/TypeErasure.ssc deleted file mode 100644 index e0852071..00000000 --- a/Source/VCExpr/TypeErasure.ssc +++ /dev/null @@ -1,1176 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// different classes for erasing complex types in VCExprs, replacing them -// with axioms that can be handled by theorem provers and SMT solvers - -namespace Microsoft.Boogie.TypeErasure -{ - using Microsoft.Boogie.VCExprAST; - - // some functionality that is needed in many places (and that should - // really be provided by the Spec# container classes; maybe one - // could integrate the functions in a nicer way?) - public class HelperFuns { - - public static Function! BoogieFunction(string! name, List! typeParams, - params Type[]! types) - requires types.Length > 0; - requires forall{int i in (0:types.Length); types[i] != null}; - { - VariableSeq! args = new VariableSeq (); - for (int i = 0; i < types.Length - 1; ++i) - args.Add(new Formal (Token.NoToken, - new TypedIdent (Token.NoToken, "arg" + i, (!)types[i]), - true)); - Formal! result = new Formal (Token.NoToken, - new TypedIdent (Token.NoToken, "res", - (!)types[types.Length - 1]), - false); - return new Function (Token.NoToken, name, ToSeq(typeParams), args, result); - } - - public static Function! BoogieFunction(string! name, params Type[]! types) { - return BoogieFunction(name, new List (), types); - } - - // boogie function where all arguments and the result have the same type U - public static Function! UniformBoogieFunction(string! name, int arity, Type! U) { - Type[]! types = new Type [arity + 1]; - for (int i = 0; i < arity + 1; ++i) - types[i] = U; - return BoogieFunction(name, types); - } - - public static List! GenVarsForInParams(Function! fun, - VCExpressionGenerator! gen) { - List! arguments = new List (fun.InParams.Length); - foreach (Formal! f in fun.InParams) { - VCExprVar! var = gen.Variable(f.Name, f.TypedIdent.Type); - arguments.Add(var); - } - return arguments; - } - - public static List! ToList (params T[]! args) { - List! res = new List (args.Length); - foreach (T t in args) - res.Add((!)t); - return res; - } - - public static List! ToList(TypeVariableSeq! seq) { - List! res = new List (seq.Length); - foreach (TypeVariable! var in seq) - res.Add(var); - return res; - } - - public static TypeVariableSeq! ToSeq(List! list) { - TypeVariableSeq! res = new TypeVariableSeq (); - foreach (TypeVariable! var in list) - res.Add(var); - return res; - } - - public static List! Intersect(List! a, List! b) { - List! res = new List (Math.Min(a.Count, b.Count)); - foreach (T x in a) - if (b.Contains(x)) - res.Add(x); - res.TrimExcess(); - return res; - } - - public static List>! ToPairList(IDictionary! dict) { - List>! res = new List> (dict); - return res; - } - - public static void AddRangeWithoutDups(IEnumerable! fromList, List! toList) { - foreach (T t in fromList) - if (!toList.Contains(t)) - toList.Add(t); - } - - public static void AddFreeVariablesWithoutDups(Type! type, List! toList) { - foreach (TypeVariable! var in type.FreeVariables) { - if (!toList.Contains(var)) - toList.Add(var); - } - } - - public static List! ToVCExprList(List! list) { - List! res = new List (list.Count); - foreach (VCExprVar! var in list) - res.Add(var); - return res; - } - - public static List! VarVector(string! baseName, int num, Type! type, - VCExpressionGenerator! gen) { - List! res = new List (num); - for (int i = 0; i < num; ++i) - res.Add(gen.Variable(baseName + i, type)); - return res; - } - - public static List! VarVector(string! baseName, List! types, - VCExpressionGenerator! gen) { - List! res = new List (types.Count); - for (int i = 0; i < types.Count; ++i) - res.Add(gen.Variable(baseName + i, types[i])); - return res; - } - } - - ////////////////////////////////////////////////////////////////////////////// - - internal struct TypeCtorRepr { - // function that represents the application of the type constructor - // to smaller types - public readonly Function! Ctor; - // left-inverse functions that extract the subtypes of a compound type - public readonly List! Dtors; - - public TypeCtorRepr(Function! ctor, List! dtors) - requires ctor.InParams.Length == dtors.Count; { - this.Ctor = ctor; - this.Dtors = dtors; - } - } - - ////////////////////////////////////////////////////////////////////////////// - - // The class responsible for creating and keeping track of all - // axioms related to the type system. This abstract class is made - // concrete in two subclasses, one for type erasure with type - // premisses in quantifiers (the semantic approach), and one for - // type erasure with explicit type arguments of polymorphic - // functions (the syntacted approach). - public abstract class TypeAxiomBuilder : ICloneable { - - protected readonly VCExpressionGenerator! Gen; - - internal abstract MapTypeAbstractionBuilder! MapTypeAbstracter { get; } - - /////////////////////////////////////////////////////////////////////////// - // Type Axioms - - // list in which all typed axioms are collected - private readonly List! AllTypeAxioms; - - // list in which type axioms are incrementally collected - private readonly List! IncTypeAxioms; - - internal void AddTypeAxiom(VCExpr! axiom) { - AllTypeAxioms.Add(axiom); - IncTypeAxioms.Add(axiom); - } - - // Return all axioms that were added since the last time NewAxioms - // was called - public VCExpr! GetNewAxioms() { - VCExpr! res = Gen.NAry(VCExpressionGenerator.AndOp, IncTypeAxioms); - IncTypeAxioms.Clear(); - return res; - } - - // mapping from a type to its constructor number/index - private readonly Function! Ctor; - private BigNum CurrentCtorNum; - - private VCExpr! GenCtorAssignment(VCExpr! typeRepr) { - if (CommandLineOptions.Clo.TypeEncodingMethod - == CommandLineOptions.TypeEncoding.None) - return VCExpressionGenerator.True; - - VCExpr! res = Gen.Eq(Gen.Function(Ctor, typeRepr), - Gen.Integer(CurrentCtorNum)); - CurrentCtorNum = CurrentCtorNum + BigNum.ONE; - return res; - } - - private VCExpr! GenCtorAssignment(Function! typeRepr) { - if (CommandLineOptions.Clo.TypeEncodingMethod - == CommandLineOptions.TypeEncoding.None) - return VCExpressionGenerator.True; - - List! quantifiedVars = HelperFuns.GenVarsForInParams(typeRepr, Gen); - VCExpr! eq = - GenCtorAssignment(Gen.Function(typeRepr, - HelperFuns.ToVCExprList(quantifiedVars))); - - if (typeRepr.InParams.Length == 0) - return eq; - - return Gen.Forall(quantifiedVars, new List (), - "ctor:" + typeRepr.Name, eq); - } - - // generate an axiom (forall x0, x1, ... :: invFun(fun(x0, x1, ...) == xi) - protected VCExpr! GenLeftInverseAxiom(Function! fun, Function! invFun, int dtorNum) { - List! quantifiedVars = HelperFuns.GenVarsForInParams(fun, Gen); - - VCExpr! funApp = Gen.Function(fun, HelperFuns.ToVCExprList(quantifiedVars)); - VCExpr! lhs = Gen.Function(invFun, funApp); - VCExpr! rhs = quantifiedVars[dtorNum]; - VCExpr! eq = Gen.Eq(lhs, rhs); - - List! triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(funApp))); - return Gen.Forall(quantifiedVars, triggers, "typeInv:" + invFun.Name, eq); - } - - /////////////////////////////////////////////////////////////////////////// - - // the type of everything that is not int, bool, or a type - private readonly TypeCtorDecl! UDecl; - public readonly Type! U; - - // the type of types - private readonly TypeCtorDecl! TDecl; - public readonly Type! T; - - public abstract Type! TypeAfterErasure(Type! type); - public abstract bool UnchangedType(Type! type); - - /////////////////////////////////////////////////////////////////////////// - // Symbols for representing types - - private readonly IDictionary! BasicTypeReprs; - - private VCExpr! GetBasicTypeRepr(Type! type) - requires type.IsBasic || type.IsBv; { - VCExpr res; - if (!BasicTypeReprs.TryGetValue(type, out res)) { - res = Gen.Function(HelperFuns.BoogieFunction(type.ToString() + "Type", T)); - AddTypeAxiom(GenCtorAssignment(res)); - BasicTypeReprs.Add(type, res); - } - return (!)res; - } - - private readonly IDictionary! TypeCtorReprs; - - internal TypeCtorRepr GetTypeCtorReprStruct(TypeCtorDecl! decl) { - TypeCtorRepr reprSet; - if (!TypeCtorReprs.TryGetValue(decl, out reprSet)) { - Function! ctor = HelperFuns.UniformBoogieFunction(decl.Name + "Type", decl.Arity, T); - AddTypeAxiom(GenCtorAssignment(ctor)); - - List! dtors = new List(decl.Arity); - for (int i = 0; i < decl.Arity; ++i) { - Function! dtor = HelperFuns.UniformBoogieFunction(decl.Name + "TypeInv" + i, 1, T); - dtors.Add(dtor); - AddTypeAxiom(GenLeftInverseAxiom(ctor, dtor, i)); - } - - reprSet = new TypeCtorRepr(ctor, dtors); - TypeCtorReprs.Add(decl, reprSet); - } - - return reprSet; - } - - public Function! GetTypeCtorRepr(TypeCtorDecl! decl) { - return GetTypeCtorReprStruct(decl).Ctor; - } - - public Function! GetTypeDtor(TypeCtorDecl! decl, int num) { - return GetTypeCtorReprStruct(decl).Dtors[num]; - } - - // mapping from free type variables to VCExpr variables - private readonly IDictionary! TypeVariableMapping; - - public VCExprVar! Typed2Untyped(TypeVariable! var) { - VCExprVar res; - if (!TypeVariableMapping.TryGetValue(var, out res)) { - res = new VCExprVar (var.Name, T); - TypeVariableMapping.Add(var, res); - } - return (!)res; - } - - - //////////////////////////////////////////////////////////////////////////// - // Symbols for representing variables and constants - - // Globally defined variables - private readonly IDictionary! Typed2UntypedVariables; - - // This method must only be used for free (unbound) variables - public VCExprVar! Typed2Untyped(VCExprVar! var) { - VCExprVar res; - if (!Typed2UntypedVariables.TryGetValue(var, out res)) { - res = Gen.Variable(var.Name, TypeAfterErasure(var.Type)); - Typed2UntypedVariables.Add(var, res); - AddVarTypeAxiom(res, var.Type); - } - return (!)res; - } - - protected abstract void AddVarTypeAxiom(VCExprVar! var, Type! originalType); - - /////////////////////////////////////////////////////////////////////////// - // Translation function from types to their term representation - - public VCExpr! Type2Term(Type! type, - IDictionary! varMapping) { - // - if (type.IsBasic || type.IsBv) { - // - return GetBasicTypeRepr(type); - // - } else if (type.IsCtor) { - // - CtorType ctype = type.AsCtor; - Function! repr = GetTypeCtorRepr(ctype.Decl); - List! args = new List (ctype.Arguments.Length); - foreach (Type! t in ctype.Arguments) - args.Add(Type2Term(t, varMapping)); - return Gen.Function(repr, args); - // - } else if (type.IsVariable) { - // - VCExpr res; - if (!varMapping.TryGetValue(type.AsVariable, out res)) - // then the variable is free and we bind it at this point to a term - // variable - res = Typed2Untyped(type.AsVariable); - return (!)res; - // - } else if (type.IsMap) { - // - return Type2Term(MapTypeAbstracter.AbstractMapType(type.AsMap), varMapping); - // - } else { - System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + type); - assert false; // please the compiler - } - } - - //////////////////////////////////////////////////////////////////////////// - - public TypeAxiomBuilder(VCExpressionGenerator! gen) { - this.Gen = gen; - AllTypeAxioms = new List (); - IncTypeAxioms = new List (); - BasicTypeReprs = new Dictionary (); - CurrentCtorNum = BigNum.ZERO; - TypeCtorReprs = new Dictionary (); - TypeVariableMapping = new Dictionary (); - Typed2UntypedVariables = new Dictionary (); - - TypeCtorDecl! uDecl = new TypeCtorDecl(Token.NoToken, "U", 0); - UDecl = uDecl; - Type! u = new CtorType (Token.NoToken, uDecl, new TypeSeq ()); - U = u; - - TypeCtorDecl! tDecl = new TypeCtorDecl(Token.NoToken, "T", 0); - TDecl = tDecl; - Type! t = new CtorType (Token.NoToken, tDecl, new TypeSeq ()); - T = t; - - Ctor = HelperFuns.BoogieFunction("Ctor", t, Type.Int); - } - - public virtual void Setup() { - GetBasicTypeRepr(Type.Int); - GetBasicTypeRepr(Type.Bool); - } - - // constructor to allow cloning - internal TypeAxiomBuilder(TypeAxiomBuilder! builder) { - Gen = builder.Gen; - AllTypeAxioms = new List (builder.AllTypeAxioms); - IncTypeAxioms = new List (builder.IncTypeAxioms); - - UDecl = builder.UDecl; - U = builder.U; - - TDecl = builder.TDecl; - T = builder.T; - - Ctor = builder.Ctor; - CurrentCtorNum = builder.CurrentCtorNum; - - BasicTypeReprs = new Dictionary (builder.BasicTypeReprs); - TypeCtorReprs = new Dictionary (builder.TypeCtorReprs); - - TypeVariableMapping = - new Dictionary (builder.TypeVariableMapping); - Typed2UntypedVariables = - new Dictionary (builder.Typed2UntypedVariables); - } - - public abstract Object! Clone(); - } - - ////////////////////////////////////////////////////////////////////////////// - - // Subclass of the TypeAxiomBuilder that provides all functionality - // to deal with native sorts of a theorem prover (that are the only - // types left after erasing all other types). Currently, these are: - // - // U ... sort of all individuals/objects/values - // T ... sort of all types - // int ... integers - // bool ... booleans - - public abstract class TypeAxiomBuilderIntBoolU : TypeAxiomBuilder { - - public TypeAxiomBuilderIntBoolU(VCExpressionGenerator! gen) { - base(gen); - TypeCasts = new Dictionary (); - } - - // constructor to allow cloning - internal TypeAxiomBuilderIntBoolU(TypeAxiomBuilderIntBoolU! builder) { - base(builder); - TypeCasts = new Dictionary (builder.TypeCasts); - } - - public override void Setup() { - base.Setup(); - - GetTypeCasts(Type.Int); - GetTypeCasts(Type.Bool); - } - - // generate inverse axioms for casts (castToU(castFromU(x)) = x, under certain premisses) - protected abstract VCExpr! GenReverseCastAxiom(Function! castToU, Function! castFromU); - - protected VCExpr! GenReverseCastEq(Function! castToU, Function! castFromU, - out VCExprVar! var, out List! triggers) { - var = Gen.Variable("x", U); - - VCExpr inner = Gen.Function(castFromU, var); - VCExpr lhs = Gen.Function(castToU, inner); - triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(inner))); - - return Gen.Eq(lhs, var); - } - - protected abstract VCExpr! GenCastTypeAxioms(Function! castToU, Function! castFromU); - - /////////////////////////////////////////////////////////////////////////// - // storage of type casts for types that are supposed to be left over in the - // VCs (like int, bool, bitvectors) - - private readonly IDictionary! TypeCasts; - - private TypeCastSet GetTypeCasts(Type! type) { - TypeCastSet res; - if (!TypeCasts.TryGetValue(type, out res)) { - Function! castToU = HelperFuns.BoogieFunction(type.ToString() + "_2_U", type, U); - Function! castFromU = HelperFuns.BoogieFunction("U_2_" + type.ToString(), U, type); - - AddTypeAxiom(GenLeftInverseAxiom(castToU, castFromU, 0)); - AddTypeAxiom(GenReverseCastAxiom(castToU, castFromU)); - AddTypeAxiom(GenCastTypeAxioms(castToU, castFromU)); - - res = new TypeCastSet (castToU, castFromU); - TypeCasts.Add(type, res); - } - return res; - } - - public Function! CastTo(Type! type) - requires UnchangedType(type); { - return GetTypeCasts(type).CastFromU; - } - - public Function! CastFrom(Type! type) - requires UnchangedType(type); { - return GetTypeCasts(type).CastToU; - } - - private struct TypeCastSet { - public readonly Function! CastToU; - public readonly Function! CastFromU; - - public TypeCastSet(Function! castToU, Function! castFromU) { - CastToU = castToU; - CastFromU = castFromU; - } - } - - public bool IsCast(Function! fun) { - if (fun.InParams.Length != 1) - return false; - Type! inType = ((!)fun.InParams[0]).TypedIdent.Type; - if (inType.Equals(U)) { - Type! outType = ((!)fun.OutParams[0]).TypedIdent.Type; - if (!TypeCasts.ContainsKey(outType)) - return false; - return fun.Equals(CastTo(outType)); - } else { - if (!TypeCasts.ContainsKey(inType)) - return false; - Type! outType = ((!)fun.OutParams[0]).TypedIdent.Type; - if (!outType.Equals(U)) - return false; - return fun.Equals(CastFrom(inType)); - } - } - - //////////////////////////////////////////////////////////////////////////// - - // the only types that we allow in "untyped" expressions are U, - // Type.Int, and Type.Bool - - public override Type! TypeAfterErasure(Type! type) { - if (UnchangedType(type)) - // these types are kept - return type; - else - // all other types are replaced by U - return U; - } - - [Pure] - public override bool UnchangedType(Type! type) { - return type.IsInt || type.IsBool || type.IsBv || (type.IsMap && CommandLineOptions.Clo.UseArrayTheory); - } - - public VCExpr! Cast(VCExpr! expr, Type! toType) - requires expr.Type.Equals(U) || UnchangedType(expr.Type); - requires toType.Equals(U) || UnchangedType(toType); - { - if (expr.Type.Equals(toType)) - return expr; - - if (toType.Equals(U)) { - return Gen.Function(CastFrom(expr.Type), expr); - } else { - assert expr.Type.Equals(U); - return Gen.Function(CastTo(toType), expr); - } - } - - public List! CastSeq(List! exprs, Type! toType) { - List! res = new List (exprs.Count); - foreach (VCExpr! expr in exprs) - res.Add(Cast(expr, toType)); - return res; - } - - - } - - ////////////////////////////////////////////////////////////////////////////// - // Class for computing most general abstractions of map types. An abstraction - // of a map type t is a maptype t' in which closed proper subtypes have been replaced - // with type variables. E.g., an abstraction of [C a, int]a would be [C a, b]a. - // We subsequently consider most general abstractions as ordinary parametrised types, - // i.e., "[C a, b]a" would be considered as a type "M b" with polymorphically typed - // access functions - // - // select(M b, C a, b) returns (a) - // store(M b, C a, b, a) returns (M b) - - internal abstract class MapTypeAbstractionBuilder { - - protected readonly TypeAxiomBuilder! AxBuilder; - protected readonly VCExpressionGenerator! Gen; - - internal MapTypeAbstractionBuilder(TypeAxiomBuilder! axBuilder, - VCExpressionGenerator! gen) { - this.AxBuilder = axBuilder; - this.Gen = gen; - AbstractionVariables = new List (); - ClassRepresentations = new Dictionary (); - } - - // constructor for cloning - internal MapTypeAbstractionBuilder(TypeAxiomBuilder! axBuilder, - VCExpressionGenerator! gen, - MapTypeAbstractionBuilder! builder) { - this.AxBuilder = axBuilder; - this.Gen = gen; - AbstractionVariables = - new List (builder.AbstractionVariables); - ClassRepresentations = - new Dictionary (builder.ClassRepresentations); - } - - /////////////////////////////////////////////////////////////////////////// - // Type variables used in the abstractions. We use the same variables in the - // same order in all abstractions in order to obtain comparable abstractions - // (equals, hashcode) - - private readonly List! AbstractionVariables; - - private TypeVariable! AbstractionVariable(int num) - requires num >= 0; { - while (AbstractionVariables.Count <= num) - AbstractionVariables.Add(new TypeVariable (Token.NoToken, - "aVar" + AbstractionVariables.Count)); - return AbstractionVariables[num]; - } - - /////////////////////////////////////////////////////////////////////////// - // The untyped representation of a class of map types, i.e., of a map type - // [A0, A1, ...] R, where the argument types and the result type - // possibly contain free type variables. For each such class, a separate type - // constructor and separate select/store functions are introduced. - - protected struct MapTypeClassRepresentation { - public readonly TypeCtorDecl! RepresentingType; - public readonly Function! Select; - public readonly Function! Store; - - public MapTypeClassRepresentation(TypeCtorDecl! representingType, - Function! select, Function! store) { - this.RepresentingType = representingType; - this.Select = select; - this.Store = store; - } - } - - private readonly IDictionary! ClassRepresentations; - - protected MapTypeClassRepresentation GetClassRepresentation(MapType! abstractedType) { - MapTypeClassRepresentation res; - if (!ClassRepresentations.TryGetValue(abstractedType, out res)) { - int num = ClassRepresentations.Count; - TypeCtorDecl! synonym = - new TypeCtorDecl(Token.NoToken, "MapType" + num, abstractedType.FreeVariables.Length); - - Function! select, store; - GenSelectStoreFunctions(abstractedType, synonym, out select, out store); - - res = new MapTypeClassRepresentation(synonym, select, store); - ClassRepresentations.Add(abstractedType, res); - } - return res; - } - - // the actual select and store functions are generated by the - // concrete subclasses of this class - protected abstract void GenSelectStoreFunctions(MapType! abstractedType, - TypeCtorDecl! synonymDecl, - out Function! select, out Function! store); - - /////////////////////////////////////////////////////////////////////////// - - public Function! Select(MapType! rawType, out TypeSeq! instantiations) { - return AbstractAndGetRepresentation(rawType, out instantiations).Select; - } - - public Function! Store(MapType! rawType, out TypeSeq! instantiations) { - return AbstractAndGetRepresentation(rawType, out instantiations).Store; - } - - private MapTypeClassRepresentation - AbstractAndGetRepresentation(MapType! rawType, out TypeSeq! instantiations) { - instantiations = new TypeSeq (); - MapType! abstraction = ThinOutMapType(rawType, instantiations); - return GetClassRepresentation(abstraction); - } - - public CtorType! AbstractMapType(MapType! rawType) { - TypeSeq! instantiations = new TypeSeq (); - MapType! abstraction = ThinOutMapType(rawType, instantiations); - - MapTypeClassRepresentation repr = GetClassRepresentation(abstraction); - assume repr.RepresentingType.Arity == instantiations.Length; - return new CtorType(Token.NoToken, repr.RepresentingType, instantiations); - } - - // TODO: cache the result of this operation - protected MapType! ThinOutMapType(MapType! rawType, - TypeSeq! instantiations) { - TypeSeq! newArguments = new TypeSeq (); - foreach (Type! subtype in rawType.Arguments) - newArguments.Add(ThinOutType(subtype, rawType.TypeParameters, - instantiations)); - Type! newResult = ThinOutType(rawType.Result, rawType.TypeParameters, - instantiations); - return new MapType(Token.NoToken, rawType.TypeParameters, newArguments, newResult); - } - - private Type! ThinOutType(Type! rawType, TypeVariableSeq! boundTypeParams, - // the instantiations of inserted type variables, - // the order corresponds to the order in which - // "AbstractionVariable(int)" delivers variables - TypeSeq! instantiations) { - - if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(rawType)) - return rawType; - - if (forall{TypeVariable! var in rawType.FreeVariables; - !boundTypeParams.Has(var)}) { - // Bingo! - // if the type does not contain any bound variables, we can simply - // replace it with a type variable - TypeVariable! abstractionVar = AbstractionVariable(instantiations.Length); - assume !boundTypeParams.Has(abstractionVar); - instantiations.Add(rawType); - return abstractionVar; - } - - if (rawType.IsVariable) { - // - // then the variable has to be bound, we cannot do anything - TypeVariable! rawVar = rawType.AsVariable; - assume boundTypeParams.Has(rawVar); - return rawVar; - // - } else if (rawType.IsMap) { - // - // recursively abstract this map type and continue abstracting - CtorType! abstraction = AbstractMapType(rawType.AsMap); - return ThinOutType(abstraction, boundTypeParams, instantiations); - // - } else if (rawType.IsCtor) { - // - // traverse the subtypes - CtorType! rawCtorType = rawType.AsCtor; - TypeSeq! newArguments = new TypeSeq (); - foreach (Type! subtype in rawCtorType.Arguments) - newArguments.Add(ThinOutType(subtype, boundTypeParams, - instantiations)); - return new CtorType(Token.NoToken, rawCtorType.Decl, newArguments); - // - } else { - System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + rawType); - return rawType; // compiler appeasement policy - } - } - - } - - ////////////////////////////////////////////////////////////////////////////// - - public class VariableBindings { - public readonly IDictionary! VCExprVarBindings; - public readonly IDictionary! TypeVariableBindings; - - public VariableBindings(IDictionary! vcExprVarBindings, - IDictionary! typeVariableBindings) { - this.VCExprVarBindings = vcExprVarBindings; - this.TypeVariableBindings = typeVariableBindings; - } - - public VariableBindings() { - this (new Dictionary (), - new Dictionary ()); - } - - public VariableBindings! Clone() { - IDictionary! newVCExprVarBindings = - new Dictionary (); - foreach (KeyValuePair pair in VCExprVarBindings) - newVCExprVarBindings.Add(pair); - IDictionary! newTypeVariableBindings = - new Dictionary (); - foreach (KeyValuePair pair in TypeVariableBindings) - newTypeVariableBindings.Add(pair); - return new VariableBindings(newVCExprVarBindings, newTypeVariableBindings); - } - } - - ////////////////////////////////////////////////////////////////////////////// - - // The central class for turning types VCExprs into untyped - // VCExprs. This class makes use of the type axiom builder to manage - // the available types and symbols. - - public abstract class TypeEraser : MutatingVCExprVisitor { - - protected readonly TypeAxiomBuilderIntBoolU! AxBuilder; - - protected abstract OpTypeEraser! OpEraser { get; } - - //////////////////////////////////////////////////////////////////////////// - - public TypeEraser(TypeAxiomBuilderIntBoolU! axBuilder, VCExpressionGenerator! gen) { - base(gen); - AxBuilder = axBuilder; - } - - public VCExpr! Erase(VCExpr! expr, int polarity) - requires polarity >= -1 && polarity <= 1; { - this.Polarity = polarity; - return Mutate(expr, new VariableBindings()); - } - - internal int Polarity = 1; // 1 for positive, -1 for negative, 0 for both - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprLiteral! node, VariableBindings! bindings) { - assume node.Type == Type.Bool || node.Type == Type.Int; - return node; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprNAry! node, VariableBindings! bindings) { - VCExprOp! op = node.Op; - if (op == VCExpressionGenerator.AndOp || op == VCExpressionGenerator.OrOp) - // more efficient on large conjunctions/disjunctions - return base.Visit(node, bindings); - - // the visitor that handles all other operators - return node.Accept(OpEraser, bindings); - } - - // this method is called by MutatingVCExprVisitor.Visit(VCExprNAry, ...) - protected override VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, - List! newSubExprs, - bool changed, - VariableBindings! bindings) { - assume originalNode.Op == VCExpressionGenerator.AndOp || - originalNode.Op == VCExpressionGenerator.OrOp; - return Gen.Function(originalNode.Op, - AxBuilder.Cast(newSubExprs[0], Type.Bool), - AxBuilder.Cast(newSubExprs[1], Type.Bool)); - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprVar! node, VariableBindings! bindings) { - VCExprVar res; - if (!bindings.VCExprVarBindings.TryGetValue(node, out res)) - return AxBuilder.Typed2Untyped(node); - return (!)res; - } - - //////////////////////////////////////////////////////////////////////////// - - protected bool IsUniversalQuantifier(VCExprQuantifier! node) { - return Polarity == 1 && node.Quan == Quantifier.EX || - Polarity == -1 && node.Quan == Quantifier.ALL; - } - - protected List! BoundVarsAfterErasure(List! oldBoundVars, - // the mapping between old and new variables - // is added to this bindings-object - VariableBindings! bindings) { - List! newBoundVars = new List (oldBoundVars.Count); - foreach (VCExprVar! var in oldBoundVars) { - Type! newType = AxBuilder.TypeAfterErasure(var.Type); - VCExprVar! newVar = Gen.Variable(var.Name, newType); - newBoundVars.Add(newVar); - bindings.VCExprVarBindings.Add(var, newVar); - } - return newBoundVars; - } - - // We check whether casts Int2U or Bool2U on the bound variables - // occur in triggers. In case a trigger like f(Int2U(x)) occurs, - // it may be better to give variable x the type U and remove the - // cast. The following method returns true if the quantifier - // should be translated again with a different typing - protected bool RedoQuantifier(VCExprQuantifier! node, - VCExprQuantifier! newNode, - // the bound vars that actually occur in the body or - // in any of the triggers - List! occurringVars, - VariableBindings! oldBindings, - out VariableBindings! newBindings, - out List! newBoundVars) { - List castVariables = - VariableCastCollector.FindCastVariables(node, newNode, AxBuilder); - if (castVariables.Count == 0) { - newBindings = oldBindings; // to make the compiler happy - newBoundVars = newNode.BoundVars; // to make the compiler happy - return false; - } - - // redo everything with a different typing ... - - newBindings = oldBindings.Clone(); - newBoundVars = new List (node.BoundVars.Count); - foreach (VCExprVar! var in node.BoundVars) { - Type! newType = - castVariables.Contains(var) ? AxBuilder.U - : AxBuilder.TypeAfterErasure(var.Type); - VCExprVar! newVar = Gen.Variable(var.Name, newType); - newBoundVars.Add(newVar); - newBindings.VCExprVarBindings.Add(var, newVar); - } - - return true; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprLet! node, VariableBindings! bindings) { - VariableBindings! newVarBindings = bindings.Clone(); - - List! newBoundVars = new List (node.BoundVars.Count); - foreach (VCExprVar! var in node.BoundVars) { - Type! newType = AxBuilder.TypeAfterErasure(var.Type); - VCExprVar! newVar = Gen.Variable(var.Name, newType); - newBoundVars.Add(newVar); - newVarBindings.VCExprVarBindings.Add(var, newVar); - } - - List! newbindings = new List (node.Length); - for (int i = 0; i < node.Length; ++i) { - VCExprLetBinding! binding = node[i]; - VCExprVar! newVar = newBoundVars[i]; - Type! newType = newVar.Type; - - VCExpr! newE = AxBuilder.Cast(Mutate(binding.E, newVarBindings), newType); - newbindings.Add(Gen.LetBinding(newVar, newE)); - } - - VCExpr! newbody = Mutate(node.Body, newVarBindings); - return Gen.Let(newbindings, newbody); - } - } - - ////////////////////////////////////////////////////////////////////////////// - - public abstract class OpTypeEraser : StandardVCExprOpVisitor { - - protected readonly TypeAxiomBuilderIntBoolU! AxBuilder; - - protected readonly TypeEraser! Eraser; - protected readonly VCExpressionGenerator! Gen; - - public OpTypeEraser(TypeEraser! eraser, TypeAxiomBuilderIntBoolU! axBuilder, - VCExpressionGenerator! gen) { - this.AxBuilder = axBuilder; - this.Eraser = eraser; - this.Gen = gen; - } - - protected override VCExpr! StandardResult(VCExprNAry! node, VariableBindings! bindings) { - System.Diagnostics.Debug.Fail("Don't know how to erase types in this expression: " + node); - assert false; // to please the compiler - } - - private List! MutateSeq(VCExprNAry! node, VariableBindings! bindings, - int newPolarity) { - int oldPolarity = Eraser.Polarity; - Eraser.Polarity = newPolarity; - List! newArgs = Eraser.MutateSeq(node, bindings); - Eraser.Polarity = oldPolarity; - return newArgs; - } - - private VCExpr! CastArguments(VCExprNAry! node, Type! argType, VariableBindings! bindings, - int newPolarity) { - return Gen.Function(node.Op, - AxBuilder.CastSeq(MutateSeq(node, bindings, newPolarity), - argType)); - } - - // Cast the arguments of the node to their old type if necessary and possible; otherwise use - // their new type (int, bool, or U) - private VCExpr! CastArgumentsToOldType(VCExprNAry! node, VariableBindings! bindings, - int newPolarity) - requires node.Arity > 0; { - - List! newArgs = MutateSeq(node, bindings, newPolarity); - Type! oldType = node[0].Type; - if (AxBuilder.UnchangedType(oldType) && - forall{int i in (1:node.Arity); node[i].Type.Equals(oldType)}) - return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, oldType)); - else - return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, AxBuilder.U)); - } - - /////////////////////////////////////////////////////////////////////////// - - public override VCExpr! VisitNotOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Bool, bindings, -Eraser.Polarity); - } - public override VCExpr! VisitEqOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArgumentsToOldType(node, bindings, 0); - } - public override VCExpr! VisitNeqOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArgumentsToOldType(node, bindings, 0); - } - public override VCExpr! VisitImpliesOp (VCExprNAry! node, VariableBindings! bindings) { - // UGLY: the code for tracking polarities should be factored out - List! newArgs = new List (2); - Eraser.Polarity = -Eraser.Polarity; - newArgs.Add(Eraser.Mutate(node[0], bindings)); - Eraser.Polarity = -Eraser.Polarity; - newArgs.Add(Eraser.Mutate(node[1], bindings)); - return Gen.Function(node.Op, AxBuilder.CastSeq(newArgs, Type.Bool)); - } - public override VCExpr! VisitDistinctOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArgumentsToOldType(node, bindings, 0); - } - public override VCExpr! VisitLabelOp (VCExprNAry! node, VariableBindings! bindings) { - // argument of the label operator should always be a formula - // (at least for Simplify ... should this be ensured at a later point?) - return CastArguments(node, Type.Bool, bindings, Eraser.Polarity); - } - public override VCExpr! VisitIfThenElseOp (VCExprNAry! node, VariableBindings! bindings) { - List! newArgs = MutateSeq(node, bindings, 0); - newArgs[0] = AxBuilder.Cast(newArgs[0], Type.Bool); - Type t = node.Type; - if (!AxBuilder.UnchangedType(t)) { - t = AxBuilder.U; - } - newArgs[1] = AxBuilder.Cast(newArgs[1], t); - newArgs[2] = AxBuilder.Cast(newArgs[2], t); - return Gen.Function(node.Op, newArgs); - } - public override VCExpr! VisitCustomOp (VCExprNAry! node, VariableBindings! bindings) { - List! newArgs = MutateSeq(node, bindings, 0); - return Gen.Function(node.Op, newArgs); - } - public override VCExpr! VisitAddOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitSubOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitMulOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitDivOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitModOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitLtOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitLeOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitGtOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitGeOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, Type.Int, bindings, 0); - } - public override VCExpr! VisitSubtypeOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArguments(node, AxBuilder.U, bindings, 0); - } - public override VCExpr! VisitBvOp (VCExprNAry! node, VariableBindings! bindings) { - return CastArgumentsToOldType(node, bindings, 0); - } - public override VCExpr! VisitBvExtractOp(VCExprNAry! node, VariableBindings! bindings) { - return CastArgumentsToOldType(node, bindings, 0); - } - public override VCExpr! VisitBvConcatOp (VCExprNAry! node, VariableBindings! bindings) { - List! newArgs = MutateSeq(node, bindings, 0); - - // each argument is cast to its old type - assert newArgs.Count == node.Arity && newArgs.Count == 2; - VCExpr! arg0 = AxBuilder.Cast(newArgs[0], node[0].Type); - VCExpr! arg1 = AxBuilder.Cast(newArgs[1], node[1].Type); - - return Gen.Function(node.Op, arg0, arg1); - } - - } - - ////////////////////////////////////////////////////////////////////////////// - - /// - /// Collect all variables x occurring in expressions of the form Int2U(x) or Bool2U(x), and - /// collect all variables x occurring outside such forms. - /// - internal class VariableCastCollector : TraversingVCExprVisitor { - /// - /// Determine those bound variables in "oldNode" all of whose relevant uses - /// have to be cast in potential triggers in "newNode". It is assume that - /// the bound variables of "oldNode" correspond to the first bound - /// variables of "newNode". - /// - public static List! FindCastVariables(VCExprQuantifier! oldNode, - VCExprQuantifier! newNode, - TypeAxiomBuilderIntBoolU! axBuilder) { - VariableCastCollector! collector = new VariableCastCollector(axBuilder); - if (exists{VCTrigger! trigger in newNode.Triggers; trigger.Pos}) { - // look in the given triggers - foreach (VCTrigger! trigger in newNode.Triggers) - if (trigger.Pos) - foreach (VCExpr! expr in trigger.Exprs) - collector.Traverse(expr, true); - } else { - // look in the body of the quantifier - collector.Traverse(newNode.Body, true); - } - - List! castVariables = new List (collector.varsInCasts.Count); - foreach (VCExprVar! castVar in collector.varsInCasts) { - int i = newNode.BoundVars.IndexOf(castVar); - if (0 <= i && i < oldNode.BoundVars.Count && !collector.varsOutsideCasts.ContainsKey(castVar)) - castVariables.Add(oldNode.BoundVars[i]); - } - return castVariables; - } - - public VariableCastCollector(TypeAxiomBuilderIntBoolU! axBuilder) { - this.AxBuilder = axBuilder; - } - - readonly List! varsInCasts = new List (); - readonly Dictionary! varsOutsideCasts = new Dictionary (); - - readonly TypeAxiomBuilderIntBoolU! AxBuilder; - - protected override bool StandardResult(VCExpr! node, bool arg) { - return true; // not used - } - - public override bool Visit(VCExprNAry! node, bool arg) { - if (node.Op is VCExprBoogieFunctionOp) { - Function! func = ((VCExprBoogieFunctionOp)node.Op).Func; - if ((AxBuilder.IsCast(func)) && node[0] is VCExprVar) { - VCExprVar castVar = (VCExprVar)node[0]; - if (!varsInCasts.Contains(castVar)) - varsInCasts.Add(castVar); - return true; - } - } else if (node.Op is VCExprNAryOp) { - VCExpressionGenerator.SingletonOp op = VCExpressionGenerator.SingletonOpDict[node.Op]; - switch(op) { - // the following operators cannot be used in triggers, so disregard any uses of variables as direct arguments - case VCExpressionGenerator.SingletonOp.NotOp: - case VCExpressionGenerator.SingletonOp.EqOp: - case VCExpressionGenerator.SingletonOp.NeqOp: - case VCExpressionGenerator.SingletonOp.AndOp: - case VCExpressionGenerator.SingletonOp.OrOp: - case VCExpressionGenerator.SingletonOp.ImpliesOp: - case VCExpressionGenerator.SingletonOp.LtOp: - case VCExpressionGenerator.SingletonOp.LeOp: - case VCExpressionGenerator.SingletonOp.GtOp: - case VCExpressionGenerator.SingletonOp.GeOp: - foreach (VCExpr n in node) { - if (!(n is VCExprVar)) { // don't recurse on VCExprVar argument - n.Accept(this, arg); - } - } - return true; - default: - break; - } - } - return base.Visit(node, arg); - } - - public override bool Visit(VCExprVar! node, bool arg) { - if (!varsOutsideCasts.ContainsKey(node)) - varsOutsideCasts.Add(node, null); - return true; - } - } - -} diff --git a/Source/VCExpr/TypeErasureArguments.cs b/Source/VCExpr/TypeErasureArguments.cs new file mode 100644 index 00000000..ec03d2e8 --- /dev/null +++ b/Source/VCExpr/TypeErasureArguments.cs @@ -0,0 +1,626 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// Erasure of types using explicit type parameters for functions + +namespace Microsoft.Boogie.TypeErasure +{ + using Microsoft.Boogie.VCExprAST; + using HFNS = Microsoft.Boogie.VCExprAST.HelperFuns; + + public class TypeAxiomBuilderArguments : TypeAxiomBuilderIntBoolU { + + public TypeAxiomBuilderArguments(VCExpressionGenerator! gen) { + base(gen); + Typed2UntypedFunctions = new Dictionary (); + } + + // constructor to allow cloning + [NotDelayed] + internal TypeAxiomBuilderArguments(TypeAxiomBuilderArguments! builder) { + Typed2UntypedFunctions = + new Dictionary (builder.Typed2UntypedFunctions); + base(builder); + + MapTypeAbstracterAttr = + builder.MapTypeAbstracterAttr == null ? + null : new MapTypeAbstractionBuilderArguments(this, builder.Gen, + builder.MapTypeAbstracterAttr); + } + + public override Object! Clone() { + return new TypeAxiomBuilderArguments(this); + } + + /////////////////////////////////////////////////////////////////////////////// + + // generate axioms of the kind "forall x:U. {Int2U(U2Int(x))} Int2U(U2Int(x))==x" + // (this makes use of the assumption that only well-typed terms are generated + // by the SMT-solver, i.e., that U2Int is only applied to terms that actually + // are of type int) + protected override VCExpr! GenReverseCastAxiom(Function! castToU, + Function! castFromU) { + List! triggers; + VCExprVar! var; + VCExpr! eq = GenReverseCastEq(castToU, castFromU, out var, out triggers); + return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, eq); + } + + protected override VCExpr! GenCastTypeAxioms(Function! castToU, + Function! castFromU) { + // nothing + return VCExpressionGenerator.True; + } + + private MapTypeAbstractionBuilderArguments MapTypeAbstracterAttr = null; + + internal override MapTypeAbstractionBuilder! MapTypeAbstracter { get { + if (MapTypeAbstracterAttr == null) + MapTypeAbstracterAttr = new MapTypeAbstractionBuilderArguments (this, Gen); + return MapTypeAbstracterAttr; + } } + + protected override void AddVarTypeAxiom(VCExprVar! var, Type! originalType) { + // no axioms are needed for variable or function types + } + + //////////////////////////////////////////////////////////////////////////// + // Symbols for representing functions + + // Globally defined functions + private readonly IDictionary! Typed2UntypedFunctions; + + public Function! Typed2Untyped(Function! fun) { + Function res; + if (!Typed2UntypedFunctions.TryGetValue(fun, out res)) { + assert fun.OutParams.Length == 1; + + // if all of the parameters are int or bool, the function does + // not have to be changed + if (forall{Formal f in fun.InParams; UnchangedType(((!)f).TypedIdent.Type)} && + UnchangedType(((!)fun.OutParams[0]).TypedIdent.Type)) { + res = fun; + } else { + Type[]! types = new Type [fun.TypeParameters.Length + fun.InParams.Length + 1]; + + int i = 0; + // the first arguments are the explicit type parameters + for (int j = 0; j < fun.TypeParameters.Length; ++j) { + types[i] = T; + i = i + 1; + } + // followed by the actual parameters + foreach (Variable! x in fun.InParams) { + types[i] = TypeAfterErasure(x.TypedIdent.Type); + i = i + 1; + } + + types[types.Length - 1] = TypeAfterErasure(((!)fun.OutParams[0]).TypedIdent.Type); + + res = HelperFuns.BoogieFunction(fun.Name, types); + res.Attributes = fun.Attributes; + } + + Typed2UntypedFunctions.Add(fun, res); + } + return (!)res; + } + + } + + ////////////////////////////////////////////////////////////////////////////// + + internal class MapTypeAbstractionBuilderArguments : MapTypeAbstractionBuilder { + + private readonly TypeAxiomBuilderArguments! AxBuilderArguments; + + internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments! axBuilder, + VCExpressionGenerator! gen) { + base(axBuilder, gen); + this.AxBuilderArguments = axBuilder; + } + + // constructor for cloning + internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments! axBuilder, + VCExpressionGenerator! gen, + MapTypeAbstractionBuilderArguments! builder) { + base(axBuilder, gen, builder); + this.AxBuilderArguments = axBuilder; + } + + //////////////////////////////////////////////////////////////////////////// + + protected override void GenSelectStoreFunctions(MapType! abstractedType, + TypeCtorDecl! synonym, + out Function! select, + out Function! store) { + string! baseName = synonym.Name; + int typeParamNum = abstractedType.FreeVariables.Length + + abstractedType.TypeParameters.Length; + + int arity = typeParamNum + abstractedType.Arguments.Length; + + Type![]! selectTypes = new Type! [arity + 2]; + Type![]! storeTypes = new Type! [arity + 3]; + + int i = 0; + // Fill in the free variables and type parameters + for (; i < typeParamNum; i++) { + selectTypes[i] = AxBuilder.T; + storeTypes[i] = AxBuilder.T; + } + // Fill in the map type + if (CommandLineOptions.Clo.UseArrayTheory) { + selectTypes[i] = abstractedType; + storeTypes[i] = abstractedType; + } else { + selectTypes[i] = AxBuilder.U; + storeTypes[i] = AxBuilder.U; + } + i++; + // Fill in the index types + foreach (Type! type in abstractedType.Arguments) + { + if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(type)) { + selectTypes[i] = type; + storeTypes[i] = type; + } else { + selectTypes[i] = AxBuilder.U; + storeTypes[i] = AxBuilder.U; + } + i++; + } + // Fill in the output type for select function which also happens + // to be the type of the last argument to the store function + if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(abstractedType.Result)) { + selectTypes[i] = abstractedType.Result; + storeTypes[i] = abstractedType.Result; + } else { + selectTypes[i] = AxBuilder.U; + storeTypes[i] = AxBuilder.U; + } + i++; + // Fill in the map type which is the output of the store function + if (CommandLineOptions.Clo.UseArrayTheory) + storeTypes[i] = abstractedType; + else + storeTypes[i] = AxBuilder.U; + NonNullType.AssertInitialized(selectTypes); + NonNullType.AssertInitialized(storeTypes); + + select = HelperFuns.BoogieFunction(baseName + "Select", selectTypes); + store = HelperFuns.BoogieFunction(baseName + "Store", storeTypes); + + if (CommandLineOptions.Clo.UseArrayTheory) { + select.AddAttribute("builtin", "select"); + store.AddAttribute("builtin", "store"); + } else { + AxBuilder.AddTypeAxiom(GenMapAxiom0(select, store, + abstractedType.TypeParameters.Length, abstractedType.FreeVariables.Length)); + AxBuilder.AddTypeAxiom(GenMapAxiom1(select, store, + abstractedType.TypeParameters.Length, abstractedType.FreeVariables.Length)); + } + } + + /////////////////////////////////////////////////////////////////////////// + // The normal axioms of the theory of arrays (right now without extensionality) + + private VCExpr! Select(Function! select, List! types, + VCExpr! map, List! indexes) { + List! selectArgs = new List (); + selectArgs.AddRange(HelperFuns.ToVCExprList(types)); + selectArgs.Add(map); + selectArgs.AddRange(HelperFuns.ToVCExprList(indexes)); + return Gen.Function(select, selectArgs); + } + + private VCExpr! Store(Function! store, List! types, + VCExpr! map, List! indexes, VCExpr! val) { + List! storeArgs = new List (); + storeArgs.AddRange(HelperFuns.ToVCExprList(types)); + storeArgs.Add(map); + storeArgs.AddRange(HelperFuns.ToVCExprList(indexes)); + storeArgs.Add(val); + return Gen.Function(store, storeArgs); + } + + private VCExpr! GenMapAxiom0(Function! select, Function! store, + // bound type variables in the map type + int mapTypeParamNum, + // free type variables in the map + // type (abstraction) + int mapAbstractionVarNum) { + int arity = select.InParams.Length - 1 - mapTypeParamNum - mapAbstractionVarNum; + List! types = + HelperFuns.VarVector("t", mapTypeParamNum + mapAbstractionVarNum, + AxBuilder.T, Gen); + + List indexTypes = new List(); + for (int i = mapTypeParamNum + mapAbstractionVarNum + 1; i < select.InParams.Length; i++) + { + indexTypes.Add(((!)select.InParams[i]).TypedIdent.Type); + } + assert arity == indexTypes.Count; + + List! indexes = HelperFuns.VarVector("x", indexTypes, Gen); + + VCExprVar! m = Gen.Variable("m", AxBuilder.U); + VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); + + VCExpr! storeExpr = Store(store, types, m, indexes, val); + VCExpr! selectExpr = Select(select, types, storeExpr, indexes); + + List! quantifiedVars = new List (); + quantifiedVars.AddRange(types); + quantifiedVars.Add(val); + quantifiedVars.Add(m); + quantifiedVars.AddRange(indexes); + + VCExpr! eq = Gen.Eq(selectExpr, val); + return Gen.Forall(quantifiedVars, new List (), + "mapAx0:" + select.Name, eq); + } + + private VCExpr! GenMapAxiom1(Function! select, Function! store, + // bound type variables in the map + // type + int mapTypeParamNum, + // free type variables in the map + // type (abstraction) + int mapAbstractionVarNum) { + int arity = select.InParams.Length - 1 - mapTypeParamNum - mapAbstractionVarNum; + + List! freeTypeVars = + HelperFuns.VarVector("u", mapAbstractionVarNum, AxBuilder.T, Gen); + List! boundTypeVars0 = + HelperFuns.VarVector("s", mapTypeParamNum, AxBuilder.T, Gen); + List! boundTypeVars1 = + HelperFuns.VarVector("t", mapTypeParamNum, AxBuilder.T, Gen); + + List! types0 = new List (boundTypeVars0); + types0.AddRange(freeTypeVars); + + List! types1 = new List (boundTypeVars1); + types1.AddRange(freeTypeVars); + + List indexTypes = new List(); + for (int i = mapTypeParamNum + mapAbstractionVarNum + 1; i < select.InParams.Length; i++) + { + indexTypes.Add(((!)select.InParams[i]).TypedIdent.Type); + } + assert arity == indexTypes.Count; + + List! indexes0 = HelperFuns.VarVector("x", indexTypes, Gen); + List! indexes1 = HelperFuns.VarVector("y", indexTypes, Gen); + + VCExprVar! m = Gen.Variable("m", AxBuilder.U); + VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); + + VCExpr! storeExpr = Store(store, types0, m, indexes0, val); + VCExpr! selectWithoutStoreExpr = Select(select, types1, m, indexes1); + VCExpr! selectExpr = Select(select, types1, storeExpr, indexes1); + + VCExpr! selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr); + + List! quantifiedVars = new List (); + quantifiedVars.AddRange(freeTypeVars); + quantifiedVars.AddRange(boundTypeVars0); + quantifiedVars.AddRange(boundTypeVars1); + quantifiedVars.Add(val); + quantifiedVars.Add(m); + quantifiedVars.AddRange(indexes0); + quantifiedVars.AddRange(indexes1); + + List! triggers = new List (); + + // different value arguments or different type arguments are sufficient + // to conclude that that value of the map at some point (after an update) + // has not changed + + List! indexEqs = new List (); + for (int i = 0; i < mapTypeParamNum; ++i) + indexEqs.Add(Gen.Eq(boundTypeVars0[i], boundTypeVars1[i])); + for (int i = 0; i < arity; ++i) + indexEqs.Add(Gen.Eq(indexes0[i], indexes1[i])); + + VCExpr! axiom = VCExpressionGenerator.True; + int n = 0; + foreach (VCExpr! indexesEq in indexEqs) { + VCExpr! matrix = Gen.Or(indexesEq, selectEq); + VCExpr! conjunct = Gen.Forall(quantifiedVars, triggers, + "mapAx1:" + select.Name + ":" + n, matrix); + axiom = Gen.AndSimp(axiom, conjunct); + n = n + 1; + } + + return axiom; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + public class TypeEraserArguments : TypeEraser { + + private readonly TypeAxiomBuilderArguments! AxBuilderArguments; + + private OpTypeEraser OpEraserAttr = null; + protected override OpTypeEraser! OpEraser { get { + if (OpEraserAttr == null) + OpEraserAttr = new OpTypeEraserArguments(this, AxBuilderArguments, Gen); + return OpEraserAttr; + } } + + public TypeEraserArguments(TypeAxiomBuilderArguments! axBuilder, + VCExpressionGenerator! gen) { + base(axBuilder, gen); + this.AxBuilderArguments = axBuilder; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprQuantifier! node, + VariableBindings! oldBindings) { + VariableBindings! bindings = oldBindings.Clone(); + + // bound term variables are replaced with bound term variables + // typed in a simpler way + List! newBoundVars = + BoundVarsAfterErasure(node.BoundVars, bindings); + + // type variables are replaced with ordinary quantified variables + GenBoundVarsForTypeParams(node.TypeParameters, newBoundVars, bindings); + VCExpr! newNode = HandleQuantifier(node, newBoundVars, bindings); + + if (!(newNode is VCExprQuantifier) || !IsUniversalQuantifier(node)) + return newNode; + + VariableBindings! bindings2; + if (!RedoQuantifier(node, (VCExprQuantifier)newNode, node.BoundVars, oldBindings, + out bindings2, out newBoundVars)) + return newNode; + + GenBoundVarsForTypeParams(node.TypeParameters, newBoundVars, bindings2); + return HandleQuantifier(node, newBoundVars, bindings2); + } + + private void GenBoundVarsForTypeParams(List! typeParams, + List! newBoundVars, + VariableBindings! bindings) { + foreach (TypeVariable! tvar in typeParams) { + VCExprVar! var = Gen.Variable(tvar.Name, AxBuilder.T); + newBoundVars.Add(var); + bindings.TypeVariableBindings.Add(tvar, var); + } + } + + private VCExpr! HandleQuantifier(VCExprQuantifier! node, + List! newBoundVars, + VariableBindings! bindings) { + List! newTriggers = MutateTriggers(node.Triggers, bindings); + VCExpr! newBody = Mutate(node.Body, bindings); + newBody = AxBuilder.Cast(newBody, Type.Bool); + + if (newBoundVars.Count == 0) // might happen that no bound variables are left + return newBody; + return Gen.Quantify(node.Quan, new List (), newBoundVars, + newTriggers, node.Infos, newBody); + } + } + + ////////////////////////////////////////////////////////////////////////////// + + public class OpTypeEraserArguments : OpTypeEraser { + + protected readonly TypeAxiomBuilderArguments! AxBuilderArguments; + + public OpTypeEraserArguments(TypeEraserArguments! eraser, + TypeAxiomBuilderArguments! axBuilder, + VCExpressionGenerator! gen) { + base(eraser, axBuilder, gen); + this.AxBuilderArguments = axBuilder; + } + + //////////////////////////////////////////////////////////////////////////// + + private VCExpr! AssembleOpExpression(OpTypesPair opTypes, + IEnumerable! oldArgs, + VariableBindings! bindings) { + // UGLY: the code for tracking polarities should be factored out + int oldPolarity = Eraser.Polarity; + Eraser.Polarity = 0; + + List! newArgs = new List (); + // explicit type parameters + foreach (Type! t in opTypes.Types) + newArgs.Add(AxBuilder.Type2Term(t, bindings.TypeVariableBindings)); + + // and the actual value parameters + Function! newFun = ((VCExprBoogieFunctionOp)opTypes.Op).Func; + // ^ we only allow this operator at this point + int i = opTypes.Types.Count; + foreach (VCExpr! arg in oldArgs) { + newArgs.Add(AxBuilder.Cast(Eraser.Mutate(arg, bindings), + ((!)newFun.InParams[i]).TypedIdent.Type)); + i = i + 1; + } + + Eraser.Polarity = oldPolarity; + return Gen.Function(opTypes.Op, newArgs); + } + + // for the time being, we store both the types of the arguments and the explicit + // type parameters (for most operators, this is more than actually necessary) + private OpTypesPair OriginalOpTypes(VCExprNAry! node) { + List! originalTypes = new List (); + foreach (VCExpr! expr in node) + originalTypes.Add(expr.Type); + originalTypes.AddRange(node.TypeArguments); + return new OpTypesPair (node.Op, originalTypes); + } + + private VCExpr! EqualTypes(Type! t0, Type! t1, VariableBindings! bindings) { + if (t0.Equals(t1)) + return VCExpressionGenerator.True; + VCExpr! t0Expr = AxBuilder.Type2Term(t0, bindings.TypeVariableBindings); + VCExpr! t1Expr = AxBuilder.Type2Term(t1, bindings.TypeVariableBindings); + return Gen.Eq(t0Expr, t1Expr); + } + + /////////////////////////////////////////////////////////////////////////// + + public override VCExpr! VisitEqOp (VCExprNAry! node, VariableBindings! bindings) { + // we also have to state that the types are equal, because the + // translation does not contain any information about the + // relationship between values and types + return Gen.AndSimp(base.VisitEqOp(node, bindings), + EqualTypes(node[0].Type, node[1].Type, bindings)); + } + + public override VCExpr! VisitNeqOp (VCExprNAry! node, VariableBindings! bindings) { + // we also have to state that the types are (un)equal, because the + // translation does not contain any information about the + // relationship between values and types + return Gen.OrSimp(base.VisitNeqOp(node, bindings), + Gen.Not(EqualTypes(node[0].Type, node[1].Type, bindings))); + } + + public override VCExpr! VisitSubtypeOp (VCExprNAry! node, VariableBindings! bindings) { + // UGLY: the code for tracking polarities should be factored out + int oldPolarity = Eraser.Polarity; + Eraser.Polarity = 0; + + VCExpr! res = + Gen.Function(VCExpressionGenerator.Subtype3Op, + AxBuilder.Type2Term(node[0].Type, + bindings.TypeVariableBindings), + AxBuilder.Cast(Eraser.Mutate(node[0], bindings), + AxBuilder.U), + AxBuilder.Cast(Eraser.Mutate(node[1], bindings), + AxBuilder.U)); + + Eraser.Polarity = oldPolarity; + return res; + } + + public override VCExpr! VisitSelectOp (VCExprNAry! node, VariableBindings! bindings) { + OpTypesPair originalOpTypes = OriginalOpTypes(node); + OpTypesPair newOpTypes; + + if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { + MapType! rawType = node[0].Type.AsMap; + TypeSeq! abstractionInstantiation; + Function! select = + AxBuilder.MapTypeAbstracter.Select(rawType, out abstractionInstantiation); + + newOpTypes = TypesPairForSelectStore(node, select, abstractionInstantiation); + NewOpCache.Add(originalOpTypes, newOpTypes); + } + + return AssembleOpExpression(newOpTypes, node, bindings); + } + + public override VCExpr! VisitStoreOp (VCExprNAry! node, VariableBindings! bindings) { + OpTypesPair originalOpTypes = OriginalOpTypes(node); + OpTypesPair newOpTypes; + + if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { + MapType! rawType = node[0].Type.AsMap; + TypeSeq! abstractionInstantiation; + Function! store = + AxBuilder.MapTypeAbstracter.Store(rawType, out abstractionInstantiation); + + newOpTypes = TypesPairForSelectStore(node, store, abstractionInstantiation); + NewOpCache.Add(originalOpTypes, newOpTypes); + } + + return AssembleOpExpression(newOpTypes, node, bindings); + } + + private OpTypesPair TypesPairForSelectStore(VCExprNAry! node, Function! untypedOp, + // instantiation of the abstract map type parameters + TypeSeq! abstractionInstantiation) { + List! inferredTypeArgs = new List (); + foreach (Type! t in node.TypeArguments) +// inferredTypeArgs.Add(AxBuilder.MapTypeAbstracter.AbstractMapTypeRecursively(t)); + inferredTypeArgs.Add(t); + foreach (Type! t in abstractionInstantiation) + inferredTypeArgs.Add(t); + + assert untypedOp.InParams.Length == inferredTypeArgs.Count + node.Arity; + return new OpTypesPair (Gen.BoogieFunctionOp(untypedOp), inferredTypeArgs); + } + + /////////////////////////////////////////////////////////////////////////// + + public override VCExpr! VisitBoogieFunctionOp (VCExprNAry! node, VariableBindings! bindings) { + OpTypesPair originalOpTypes = OriginalOpTypes(node); + OpTypesPair newOpTypes; + + if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { + Function! oriFun = ((VCExprBoogieFunctionOp)node.Op).Func; + + List! inferredTypeArgs = new List (); + foreach (Type! t in node.TypeArguments) +// inferredTypeArgs.Add(AxBuilder.MapTypeAbstracter.AbstractMapTypeRecursively(t)); + inferredTypeArgs.Add(t); + + VCExprOp! newOp = Gen.BoogieFunctionOp(AxBuilderArguments.Typed2Untyped(oriFun)); + newOpTypes = new OpTypesPair (newOp, inferredTypeArgs); + + NewOpCache.Add(originalOpTypes, newOpTypes); + } + + return AssembleOpExpression(newOpTypes, node, bindings); + } + + /////////////////////////////////////////////////////////////////////////// + + // cache from the typed operators to the untyped operators with + // explicit type arguments. the keys are pairs of the typed + // operator and the actual types of the argument expressions, the + // values are pairs of the new operators and the types that have + // to be given as explicit type arguments + private readonly IDictionary! NewOpCache = + new Dictionary(); + + private struct OpTypesPair { + public readonly VCExprOp! Op; + public readonly List! Types; + + public OpTypesPair(VCExprOp! op, List! types) { + this.Op = op; + this.Types = types; + this.HashCode = HFNS.PolyHash(op.GetHashCode(), 17, types); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (that is OpTypesPair) { + OpTypesPair thatPair = (OpTypesPair)that; + return this.Op.Equals(thatPair.Op) && + HFNS.SameElements(this.Types, thatPair.Types); + } + return false; + } + + private readonly int HashCode; + + [Pure] + public override int GetHashCode() { + return HashCode; + } + } + } + +} diff --git a/Source/VCExpr/TypeErasureArguments.ssc b/Source/VCExpr/TypeErasureArguments.ssc deleted file mode 100644 index ec03d2e8..00000000 --- a/Source/VCExpr/TypeErasureArguments.ssc +++ /dev/null @@ -1,626 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// Erasure of types using explicit type parameters for functions - -namespace Microsoft.Boogie.TypeErasure -{ - using Microsoft.Boogie.VCExprAST; - using HFNS = Microsoft.Boogie.VCExprAST.HelperFuns; - - public class TypeAxiomBuilderArguments : TypeAxiomBuilderIntBoolU { - - public TypeAxiomBuilderArguments(VCExpressionGenerator! gen) { - base(gen); - Typed2UntypedFunctions = new Dictionary (); - } - - // constructor to allow cloning - [NotDelayed] - internal TypeAxiomBuilderArguments(TypeAxiomBuilderArguments! builder) { - Typed2UntypedFunctions = - new Dictionary (builder.Typed2UntypedFunctions); - base(builder); - - MapTypeAbstracterAttr = - builder.MapTypeAbstracterAttr == null ? - null : new MapTypeAbstractionBuilderArguments(this, builder.Gen, - builder.MapTypeAbstracterAttr); - } - - public override Object! Clone() { - return new TypeAxiomBuilderArguments(this); - } - - /////////////////////////////////////////////////////////////////////////////// - - // generate axioms of the kind "forall x:U. {Int2U(U2Int(x))} Int2U(U2Int(x))==x" - // (this makes use of the assumption that only well-typed terms are generated - // by the SMT-solver, i.e., that U2Int is only applied to terms that actually - // are of type int) - protected override VCExpr! GenReverseCastAxiom(Function! castToU, - Function! castFromU) { - List! triggers; - VCExprVar! var; - VCExpr! eq = GenReverseCastEq(castToU, castFromU, out var, out triggers); - return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, eq); - } - - protected override VCExpr! GenCastTypeAxioms(Function! castToU, - Function! castFromU) { - // nothing - return VCExpressionGenerator.True; - } - - private MapTypeAbstractionBuilderArguments MapTypeAbstracterAttr = null; - - internal override MapTypeAbstractionBuilder! MapTypeAbstracter { get { - if (MapTypeAbstracterAttr == null) - MapTypeAbstracterAttr = new MapTypeAbstractionBuilderArguments (this, Gen); - return MapTypeAbstracterAttr; - } } - - protected override void AddVarTypeAxiom(VCExprVar! var, Type! originalType) { - // no axioms are needed for variable or function types - } - - //////////////////////////////////////////////////////////////////////////// - // Symbols for representing functions - - // Globally defined functions - private readonly IDictionary! Typed2UntypedFunctions; - - public Function! Typed2Untyped(Function! fun) { - Function res; - if (!Typed2UntypedFunctions.TryGetValue(fun, out res)) { - assert fun.OutParams.Length == 1; - - // if all of the parameters are int or bool, the function does - // not have to be changed - if (forall{Formal f in fun.InParams; UnchangedType(((!)f).TypedIdent.Type)} && - UnchangedType(((!)fun.OutParams[0]).TypedIdent.Type)) { - res = fun; - } else { - Type[]! types = new Type [fun.TypeParameters.Length + fun.InParams.Length + 1]; - - int i = 0; - // the first arguments are the explicit type parameters - for (int j = 0; j < fun.TypeParameters.Length; ++j) { - types[i] = T; - i = i + 1; - } - // followed by the actual parameters - foreach (Variable! x in fun.InParams) { - types[i] = TypeAfterErasure(x.TypedIdent.Type); - i = i + 1; - } - - types[types.Length - 1] = TypeAfterErasure(((!)fun.OutParams[0]).TypedIdent.Type); - - res = HelperFuns.BoogieFunction(fun.Name, types); - res.Attributes = fun.Attributes; - } - - Typed2UntypedFunctions.Add(fun, res); - } - return (!)res; - } - - } - - ////////////////////////////////////////////////////////////////////////////// - - internal class MapTypeAbstractionBuilderArguments : MapTypeAbstractionBuilder { - - private readonly TypeAxiomBuilderArguments! AxBuilderArguments; - - internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments! axBuilder, - VCExpressionGenerator! gen) { - base(axBuilder, gen); - this.AxBuilderArguments = axBuilder; - } - - // constructor for cloning - internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments! axBuilder, - VCExpressionGenerator! gen, - MapTypeAbstractionBuilderArguments! builder) { - base(axBuilder, gen, builder); - this.AxBuilderArguments = axBuilder; - } - - //////////////////////////////////////////////////////////////////////////// - - protected override void GenSelectStoreFunctions(MapType! abstractedType, - TypeCtorDecl! synonym, - out Function! select, - out Function! store) { - string! baseName = synonym.Name; - int typeParamNum = abstractedType.FreeVariables.Length + - abstractedType.TypeParameters.Length; - - int arity = typeParamNum + abstractedType.Arguments.Length; - - Type![]! selectTypes = new Type! [arity + 2]; - Type![]! storeTypes = new Type! [arity + 3]; - - int i = 0; - // Fill in the free variables and type parameters - for (; i < typeParamNum; i++) { - selectTypes[i] = AxBuilder.T; - storeTypes[i] = AxBuilder.T; - } - // Fill in the map type - if (CommandLineOptions.Clo.UseArrayTheory) { - selectTypes[i] = abstractedType; - storeTypes[i] = abstractedType; - } else { - selectTypes[i] = AxBuilder.U; - storeTypes[i] = AxBuilder.U; - } - i++; - // Fill in the index types - foreach (Type! type in abstractedType.Arguments) - { - if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(type)) { - selectTypes[i] = type; - storeTypes[i] = type; - } else { - selectTypes[i] = AxBuilder.U; - storeTypes[i] = AxBuilder.U; - } - i++; - } - // Fill in the output type for select function which also happens - // to be the type of the last argument to the store function - if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(abstractedType.Result)) { - selectTypes[i] = abstractedType.Result; - storeTypes[i] = abstractedType.Result; - } else { - selectTypes[i] = AxBuilder.U; - storeTypes[i] = AxBuilder.U; - } - i++; - // Fill in the map type which is the output of the store function - if (CommandLineOptions.Clo.UseArrayTheory) - storeTypes[i] = abstractedType; - else - storeTypes[i] = AxBuilder.U; - NonNullType.AssertInitialized(selectTypes); - NonNullType.AssertInitialized(storeTypes); - - select = HelperFuns.BoogieFunction(baseName + "Select", selectTypes); - store = HelperFuns.BoogieFunction(baseName + "Store", storeTypes); - - if (CommandLineOptions.Clo.UseArrayTheory) { - select.AddAttribute("builtin", "select"); - store.AddAttribute("builtin", "store"); - } else { - AxBuilder.AddTypeAxiom(GenMapAxiom0(select, store, - abstractedType.TypeParameters.Length, abstractedType.FreeVariables.Length)); - AxBuilder.AddTypeAxiom(GenMapAxiom1(select, store, - abstractedType.TypeParameters.Length, abstractedType.FreeVariables.Length)); - } - } - - /////////////////////////////////////////////////////////////////////////// - // The normal axioms of the theory of arrays (right now without extensionality) - - private VCExpr! Select(Function! select, List! types, - VCExpr! map, List! indexes) { - List! selectArgs = new List (); - selectArgs.AddRange(HelperFuns.ToVCExprList(types)); - selectArgs.Add(map); - selectArgs.AddRange(HelperFuns.ToVCExprList(indexes)); - return Gen.Function(select, selectArgs); - } - - private VCExpr! Store(Function! store, List! types, - VCExpr! map, List! indexes, VCExpr! val) { - List! storeArgs = new List (); - storeArgs.AddRange(HelperFuns.ToVCExprList(types)); - storeArgs.Add(map); - storeArgs.AddRange(HelperFuns.ToVCExprList(indexes)); - storeArgs.Add(val); - return Gen.Function(store, storeArgs); - } - - private VCExpr! GenMapAxiom0(Function! select, Function! store, - // bound type variables in the map type - int mapTypeParamNum, - // free type variables in the map - // type (abstraction) - int mapAbstractionVarNum) { - int arity = select.InParams.Length - 1 - mapTypeParamNum - mapAbstractionVarNum; - List! types = - HelperFuns.VarVector("t", mapTypeParamNum + mapAbstractionVarNum, - AxBuilder.T, Gen); - - List indexTypes = new List(); - for (int i = mapTypeParamNum + mapAbstractionVarNum + 1; i < select.InParams.Length; i++) - { - indexTypes.Add(((!)select.InParams[i]).TypedIdent.Type); - } - assert arity == indexTypes.Count; - - List! indexes = HelperFuns.VarVector("x", indexTypes, Gen); - - VCExprVar! m = Gen.Variable("m", AxBuilder.U); - VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); - - VCExpr! storeExpr = Store(store, types, m, indexes, val); - VCExpr! selectExpr = Select(select, types, storeExpr, indexes); - - List! quantifiedVars = new List (); - quantifiedVars.AddRange(types); - quantifiedVars.Add(val); - quantifiedVars.Add(m); - quantifiedVars.AddRange(indexes); - - VCExpr! eq = Gen.Eq(selectExpr, val); - return Gen.Forall(quantifiedVars, new List (), - "mapAx0:" + select.Name, eq); - } - - private VCExpr! GenMapAxiom1(Function! select, Function! store, - // bound type variables in the map - // type - int mapTypeParamNum, - // free type variables in the map - // type (abstraction) - int mapAbstractionVarNum) { - int arity = select.InParams.Length - 1 - mapTypeParamNum - mapAbstractionVarNum; - - List! freeTypeVars = - HelperFuns.VarVector("u", mapAbstractionVarNum, AxBuilder.T, Gen); - List! boundTypeVars0 = - HelperFuns.VarVector("s", mapTypeParamNum, AxBuilder.T, Gen); - List! boundTypeVars1 = - HelperFuns.VarVector("t", mapTypeParamNum, AxBuilder.T, Gen); - - List! types0 = new List (boundTypeVars0); - types0.AddRange(freeTypeVars); - - List! types1 = new List (boundTypeVars1); - types1.AddRange(freeTypeVars); - - List indexTypes = new List(); - for (int i = mapTypeParamNum + mapAbstractionVarNum + 1; i < select.InParams.Length; i++) - { - indexTypes.Add(((!)select.InParams[i]).TypedIdent.Type); - } - assert arity == indexTypes.Count; - - List! indexes0 = HelperFuns.VarVector("x", indexTypes, Gen); - List! indexes1 = HelperFuns.VarVector("y", indexTypes, Gen); - - VCExprVar! m = Gen.Variable("m", AxBuilder.U); - VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); - - VCExpr! storeExpr = Store(store, types0, m, indexes0, val); - VCExpr! selectWithoutStoreExpr = Select(select, types1, m, indexes1); - VCExpr! selectExpr = Select(select, types1, storeExpr, indexes1); - - VCExpr! selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr); - - List! quantifiedVars = new List (); - quantifiedVars.AddRange(freeTypeVars); - quantifiedVars.AddRange(boundTypeVars0); - quantifiedVars.AddRange(boundTypeVars1); - quantifiedVars.Add(val); - quantifiedVars.Add(m); - quantifiedVars.AddRange(indexes0); - quantifiedVars.AddRange(indexes1); - - List! triggers = new List (); - - // different value arguments or different type arguments are sufficient - // to conclude that that value of the map at some point (after an update) - // has not changed - - List! indexEqs = new List (); - for (int i = 0; i < mapTypeParamNum; ++i) - indexEqs.Add(Gen.Eq(boundTypeVars0[i], boundTypeVars1[i])); - for (int i = 0; i < arity; ++i) - indexEqs.Add(Gen.Eq(indexes0[i], indexes1[i])); - - VCExpr! axiom = VCExpressionGenerator.True; - int n = 0; - foreach (VCExpr! indexesEq in indexEqs) { - VCExpr! matrix = Gen.Or(indexesEq, selectEq); - VCExpr! conjunct = Gen.Forall(quantifiedVars, triggers, - "mapAx1:" + select.Name + ":" + n, matrix); - axiom = Gen.AndSimp(axiom, conjunct); - n = n + 1; - } - - return axiom; - } - } - - ////////////////////////////////////////////////////////////////////////////// - - public class TypeEraserArguments : TypeEraser { - - private readonly TypeAxiomBuilderArguments! AxBuilderArguments; - - private OpTypeEraser OpEraserAttr = null; - protected override OpTypeEraser! OpEraser { get { - if (OpEraserAttr == null) - OpEraserAttr = new OpTypeEraserArguments(this, AxBuilderArguments, Gen); - return OpEraserAttr; - } } - - public TypeEraserArguments(TypeAxiomBuilderArguments! axBuilder, - VCExpressionGenerator! gen) { - base(axBuilder, gen); - this.AxBuilderArguments = axBuilder; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprQuantifier! node, - VariableBindings! oldBindings) { - VariableBindings! bindings = oldBindings.Clone(); - - // bound term variables are replaced with bound term variables - // typed in a simpler way - List! newBoundVars = - BoundVarsAfterErasure(node.BoundVars, bindings); - - // type variables are replaced with ordinary quantified variables - GenBoundVarsForTypeParams(node.TypeParameters, newBoundVars, bindings); - VCExpr! newNode = HandleQuantifier(node, newBoundVars, bindings); - - if (!(newNode is VCExprQuantifier) || !IsUniversalQuantifier(node)) - return newNode; - - VariableBindings! bindings2; - if (!RedoQuantifier(node, (VCExprQuantifier)newNode, node.BoundVars, oldBindings, - out bindings2, out newBoundVars)) - return newNode; - - GenBoundVarsForTypeParams(node.TypeParameters, newBoundVars, bindings2); - return HandleQuantifier(node, newBoundVars, bindings2); - } - - private void GenBoundVarsForTypeParams(List! typeParams, - List! newBoundVars, - VariableBindings! bindings) { - foreach (TypeVariable! tvar in typeParams) { - VCExprVar! var = Gen.Variable(tvar.Name, AxBuilder.T); - newBoundVars.Add(var); - bindings.TypeVariableBindings.Add(tvar, var); - } - } - - private VCExpr! HandleQuantifier(VCExprQuantifier! node, - List! newBoundVars, - VariableBindings! bindings) { - List! newTriggers = MutateTriggers(node.Triggers, bindings); - VCExpr! newBody = Mutate(node.Body, bindings); - newBody = AxBuilder.Cast(newBody, Type.Bool); - - if (newBoundVars.Count == 0) // might happen that no bound variables are left - return newBody; - return Gen.Quantify(node.Quan, new List (), newBoundVars, - newTriggers, node.Infos, newBody); - } - } - - ////////////////////////////////////////////////////////////////////////////// - - public class OpTypeEraserArguments : OpTypeEraser { - - protected readonly TypeAxiomBuilderArguments! AxBuilderArguments; - - public OpTypeEraserArguments(TypeEraserArguments! eraser, - TypeAxiomBuilderArguments! axBuilder, - VCExpressionGenerator! gen) { - base(eraser, axBuilder, gen); - this.AxBuilderArguments = axBuilder; - } - - //////////////////////////////////////////////////////////////////////////// - - private VCExpr! AssembleOpExpression(OpTypesPair opTypes, - IEnumerable! oldArgs, - VariableBindings! bindings) { - // UGLY: the code for tracking polarities should be factored out - int oldPolarity = Eraser.Polarity; - Eraser.Polarity = 0; - - List! newArgs = new List (); - // explicit type parameters - foreach (Type! t in opTypes.Types) - newArgs.Add(AxBuilder.Type2Term(t, bindings.TypeVariableBindings)); - - // and the actual value parameters - Function! newFun = ((VCExprBoogieFunctionOp)opTypes.Op).Func; - // ^ we only allow this operator at this point - int i = opTypes.Types.Count; - foreach (VCExpr! arg in oldArgs) { - newArgs.Add(AxBuilder.Cast(Eraser.Mutate(arg, bindings), - ((!)newFun.InParams[i]).TypedIdent.Type)); - i = i + 1; - } - - Eraser.Polarity = oldPolarity; - return Gen.Function(opTypes.Op, newArgs); - } - - // for the time being, we store both the types of the arguments and the explicit - // type parameters (for most operators, this is more than actually necessary) - private OpTypesPair OriginalOpTypes(VCExprNAry! node) { - List! originalTypes = new List (); - foreach (VCExpr! expr in node) - originalTypes.Add(expr.Type); - originalTypes.AddRange(node.TypeArguments); - return new OpTypesPair (node.Op, originalTypes); - } - - private VCExpr! EqualTypes(Type! t0, Type! t1, VariableBindings! bindings) { - if (t0.Equals(t1)) - return VCExpressionGenerator.True; - VCExpr! t0Expr = AxBuilder.Type2Term(t0, bindings.TypeVariableBindings); - VCExpr! t1Expr = AxBuilder.Type2Term(t1, bindings.TypeVariableBindings); - return Gen.Eq(t0Expr, t1Expr); - } - - /////////////////////////////////////////////////////////////////////////// - - public override VCExpr! VisitEqOp (VCExprNAry! node, VariableBindings! bindings) { - // we also have to state that the types are equal, because the - // translation does not contain any information about the - // relationship between values and types - return Gen.AndSimp(base.VisitEqOp(node, bindings), - EqualTypes(node[0].Type, node[1].Type, bindings)); - } - - public override VCExpr! VisitNeqOp (VCExprNAry! node, VariableBindings! bindings) { - // we also have to state that the types are (un)equal, because the - // translation does not contain any information about the - // relationship between values and types - return Gen.OrSimp(base.VisitNeqOp(node, bindings), - Gen.Not(EqualTypes(node[0].Type, node[1].Type, bindings))); - } - - public override VCExpr! VisitSubtypeOp (VCExprNAry! node, VariableBindings! bindings) { - // UGLY: the code for tracking polarities should be factored out - int oldPolarity = Eraser.Polarity; - Eraser.Polarity = 0; - - VCExpr! res = - Gen.Function(VCExpressionGenerator.Subtype3Op, - AxBuilder.Type2Term(node[0].Type, - bindings.TypeVariableBindings), - AxBuilder.Cast(Eraser.Mutate(node[0], bindings), - AxBuilder.U), - AxBuilder.Cast(Eraser.Mutate(node[1], bindings), - AxBuilder.U)); - - Eraser.Polarity = oldPolarity; - return res; - } - - public override VCExpr! VisitSelectOp (VCExprNAry! node, VariableBindings! bindings) { - OpTypesPair originalOpTypes = OriginalOpTypes(node); - OpTypesPair newOpTypes; - - if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { - MapType! rawType = node[0].Type.AsMap; - TypeSeq! abstractionInstantiation; - Function! select = - AxBuilder.MapTypeAbstracter.Select(rawType, out abstractionInstantiation); - - newOpTypes = TypesPairForSelectStore(node, select, abstractionInstantiation); - NewOpCache.Add(originalOpTypes, newOpTypes); - } - - return AssembleOpExpression(newOpTypes, node, bindings); - } - - public override VCExpr! VisitStoreOp (VCExprNAry! node, VariableBindings! bindings) { - OpTypesPair originalOpTypes = OriginalOpTypes(node); - OpTypesPair newOpTypes; - - if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { - MapType! rawType = node[0].Type.AsMap; - TypeSeq! abstractionInstantiation; - Function! store = - AxBuilder.MapTypeAbstracter.Store(rawType, out abstractionInstantiation); - - newOpTypes = TypesPairForSelectStore(node, store, abstractionInstantiation); - NewOpCache.Add(originalOpTypes, newOpTypes); - } - - return AssembleOpExpression(newOpTypes, node, bindings); - } - - private OpTypesPair TypesPairForSelectStore(VCExprNAry! node, Function! untypedOp, - // instantiation of the abstract map type parameters - TypeSeq! abstractionInstantiation) { - List! inferredTypeArgs = new List (); - foreach (Type! t in node.TypeArguments) -// inferredTypeArgs.Add(AxBuilder.MapTypeAbstracter.AbstractMapTypeRecursively(t)); - inferredTypeArgs.Add(t); - foreach (Type! t in abstractionInstantiation) - inferredTypeArgs.Add(t); - - assert untypedOp.InParams.Length == inferredTypeArgs.Count + node.Arity; - return new OpTypesPair (Gen.BoogieFunctionOp(untypedOp), inferredTypeArgs); - } - - /////////////////////////////////////////////////////////////////////////// - - public override VCExpr! VisitBoogieFunctionOp (VCExprNAry! node, VariableBindings! bindings) { - OpTypesPair originalOpTypes = OriginalOpTypes(node); - OpTypesPair newOpTypes; - - if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) { - Function! oriFun = ((VCExprBoogieFunctionOp)node.Op).Func; - - List! inferredTypeArgs = new List (); - foreach (Type! t in node.TypeArguments) -// inferredTypeArgs.Add(AxBuilder.MapTypeAbstracter.AbstractMapTypeRecursively(t)); - inferredTypeArgs.Add(t); - - VCExprOp! newOp = Gen.BoogieFunctionOp(AxBuilderArguments.Typed2Untyped(oriFun)); - newOpTypes = new OpTypesPair (newOp, inferredTypeArgs); - - NewOpCache.Add(originalOpTypes, newOpTypes); - } - - return AssembleOpExpression(newOpTypes, node, bindings); - } - - /////////////////////////////////////////////////////////////////////////// - - // cache from the typed operators to the untyped operators with - // explicit type arguments. the keys are pairs of the typed - // operator and the actual types of the argument expressions, the - // values are pairs of the new operators and the types that have - // to be given as explicit type arguments - private readonly IDictionary! NewOpCache = - new Dictionary(); - - private struct OpTypesPair { - public readonly VCExprOp! Op; - public readonly List! Types; - - public OpTypesPair(VCExprOp! op, List! types) { - this.Op = op; - this.Types = types; - this.HashCode = HFNS.PolyHash(op.GetHashCode(), 17, types); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (that is OpTypesPair) { - OpTypesPair thatPair = (OpTypesPair)that; - return this.Op.Equals(thatPair.Op) && - HFNS.SameElements(this.Types, thatPair.Types); - } - return false; - } - - private readonly int HashCode; - - [Pure] - public override int GetHashCode() { - return HashCode; - } - } - } - -} diff --git a/Source/VCExpr/TypeErasurePremisses.cs b/Source/VCExpr/TypeErasurePremisses.cs new file mode 100644 index 00000000..61144209 --- /dev/null +++ b/Source/VCExpr/TypeErasurePremisses.cs @@ -0,0 +1,1080 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// Erasure of types using premisses (forall x :: type(x)=T ==> p(x)) + +namespace Microsoft.Boogie.TypeErasure +{ + using Microsoft.Boogie.VCExprAST; + + // When using type premisses, we can distinguish two kinds of type + // parameters of a function or map: parameters that occur in the + // formal argument types of the function are "implicit" because they + // can be inferred from the actual argument types; parameters that + // only occur in the result type of the function are "explicit" + // because they are not inferrable and have to be given to the + // function as additional arguments. + // + // The following structure is used to store the untyped version of a + // typed function, together with the lists of implicit and explicit + // type parameters (in the same order as they occur in the signature + // of the original function). + + internal struct UntypedFunction { + public readonly Function! Fun; + // type parameters that can be extracted from the value parameters + public readonly List! ImplicitTypeParams; + // type parameters that have to be given explicitly + public readonly List! ExplicitTypeParams; + + public UntypedFunction(Function! fun, + List! implicitTypeParams, + List! explicitTypeParams) { + Fun = fun; + ImplicitTypeParams = implicitTypeParams; + ExplicitTypeParams = explicitTypeParams; + } + } + + public class TypeAxiomBuilderPremisses : TypeAxiomBuilderIntBoolU { + + public TypeAxiomBuilderPremisses(VCExpressionGenerator! gen) { + base(gen); + TypeFunction = HelperFuns.BoogieFunction("dummy", Type.Int); + Typed2UntypedFunctions = new Dictionary (); + MapTypeAbstracterAttr = null; + } + + // constructor to allow cloning + [NotDelayed] + internal TypeAxiomBuilderPremisses(TypeAxiomBuilderPremisses! builder) { + TypeFunction = builder.TypeFunction; + Typed2UntypedFunctions = + new Dictionary (builder.Typed2UntypedFunctions); + base(builder); + + MapTypeAbstracterAttr = + builder.MapTypeAbstracterAttr == null ? + null : new MapTypeAbstractionBuilderPremisses(this, builder.Gen, + builder.MapTypeAbstracterAttr); + } + + public override Object! Clone() { + return new TypeAxiomBuilderPremisses(this); + } + + public override void Setup() { + TypeFunction = HelperFuns.BoogieFunction("type", U, T); + base.Setup(); + } + + //////////////////////////////////////////////////////////////////////////// + + // generate axioms of the kind "forall x:U. {Int2U(U2Int(x))} + // type(x)=int ==> Int2U(U2Int(x))==x" + protected override VCExpr! GenReverseCastAxiom(Function! castToU, Function! castFromU) { + List! triggers; + VCExprVar! var; + VCExpr! eq = GenReverseCastEq(castToU, castFromU, out var, out triggers); + VCExpr! premiss; + if (CommandLineOptions.Clo.TypeEncodingMethod + == CommandLineOptions.TypeEncoding.None) + premiss = VCExpressionGenerator.True; + else + premiss = GenVarTypeAxiom(var, ((!)castFromU.OutParams[0]).TypedIdent.Type, + // we don't have any bindings available + new Dictionary ()); + VCExpr! matrix = Gen.ImpliesSimp(premiss, eq); + return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, matrix); + } + + protected override VCExpr! GenCastTypeAxioms(Function! castToU, Function! castFromU) { + Type! fromType = ((!)castToU.InParams[0]).TypedIdent.Type; + return GenFunctionAxiom(castToU, new List (), new List (), + HelperFuns.ToList(fromType), fromType); + } + + private MapTypeAbstractionBuilderPremisses MapTypeAbstracterAttr; + + internal override MapTypeAbstractionBuilder! MapTypeAbstracter { get { + if (MapTypeAbstracterAttr == null) + MapTypeAbstracterAttr = new MapTypeAbstractionBuilderPremisses (this, Gen); + return MapTypeAbstracterAttr; + } } + + internal MapTypeAbstractionBuilderPremisses! MapTypeAbstracterPremisses { get { + return (MapTypeAbstractionBuilderPremisses)MapTypeAbstracter; + } } + + //////////////////////////////////////////////////////////////////////////// + + // function that maps individuals to their type + // the field is overwritten with its actual value in "Setup" + private Function! TypeFunction; + + public VCExpr! TypeOf(VCExpr! expr) { + return Gen.Function(TypeFunction, expr); + } + + /////////////////////////////////////////////////////////////////////////// + // Generate type premisses and type parameter bindings for quantifiers, functions, procedures + + // let-bindings to extract the instantiations of type parameters + public List! + GenTypeParamBindings(// the original bound variables and (implicit) type parameters + List! typeParams, List! oldBoundVars, + // VariableBindings to which the translation + // TypeVariable -> VCExprVar is added + VariableBindings! bindings, + bool addTypeVarsToBindings) { + // type variables are replaced with ordinary variables that are bound using a + // let-expression + if (addTypeVarsToBindings) { + foreach (TypeVariable! tvar in typeParams) + bindings.TypeVariableBindings.Add(tvar, Gen.Variable(tvar.Name, T)); + } + + // extract the values of type variables from the term variables + List! UtypedVars = new List (oldBoundVars.Count); + List! originalTypes = new List (oldBoundVars.Count); + foreach (VCExprVar var in oldBoundVars) { + VCExprVar! newVar = bindings.VCExprVarBindings[var]; + if (newVar.Type.Equals(U)) { + UtypedVars.Add(newVar); + originalTypes.Add(var.Type); + } + } + + UtypedVars.TrimExcess(); + originalTypes.TrimExcess(); + + return BestTypeVarExtractors(typeParams, originalTypes, UtypedVars, bindings); + } + + + public VCExpr! AddTypePremisses(List! typeVarBindings, + VCExpr! typePremisses, bool universal, + VCExpr! body) { + VCExpr! bodyWithPremisses; + if (universal) + bodyWithPremisses = Gen.ImpliesSimp(typePremisses, body); + else + bodyWithPremisses = Gen.AndSimp(typePremisses, body); + + return Gen.Let(typeVarBindings, bodyWithPremisses); + } + + + /////////////////////////////////////////////////////////////////////////// + // Extract the instantiations of type variables from the concrete types of + // term variables. E.g., for a function f(x : C a), we would extract the + // instantiation of "a" by looking at the concrete type of "x". + + public List! + BestTypeVarExtractors(List! vars, List! types, + List! concreteTypeSources, + VariableBindings! bindings) { + List! typeParamBindings = new List (); + foreach (TypeVariable! var in vars) { + VCExpr extractor = BestTypeVarExtractor(var, types, concreteTypeSources); + if (extractor != null) + typeParamBindings.Add( + Gen.LetBinding((VCExprVar)bindings.TypeVariableBindings[var], + extractor)); + } + return typeParamBindings; + } + + private VCExpr BestTypeVarExtractor(TypeVariable! var, List! types, + List! concreteTypeSources) { + List allExtractors = TypeVarExtractors(var, types, concreteTypeSources); + if (allExtractors.Count == 0) + return null; + + VCExpr bestExtractor = allExtractors[0]; + int bestExtractorSize = SizeComputingVisitor.ComputeSize(bestExtractor); + for (int i = 1; i < allExtractors.Count; ++i) { + int newSize = SizeComputingVisitor.ComputeSize(allExtractors[i]); + if (newSize < bestExtractorSize) { + bestExtractor = allExtractors[i]; + bestExtractorSize = newSize; + } + } + + return bestExtractor; + } + + private List! TypeVarExtractors(TypeVariable! var, List! types, + List! concreteTypeSources) + requires types.Count == concreteTypeSources.Count; { + List! res = new List(); + for (int i = 0; i < types.Count; ++i) + TypeVarExtractors(var, types[i], TypeOf(concreteTypeSources[i]), res); + + return res; + } + + private void TypeVarExtractors(TypeVariable! var, Type! completeType, + VCExpr! innerTerm, List! extractors) { + if (completeType.IsVariable) { + if (var.Equals(completeType)) { + extractors.Add(innerTerm); + } // else nothing + } else if (completeType.IsBasic) { + // nothing + } else if (completeType.IsCtor) { + CtorType! ctorType = completeType.AsCtor; + if (ctorType.Arguments.Length > 0) { + // otherwise there are no chances of extracting any + // instantiations from this type + TypeCtorRepr repr = GetTypeCtorReprStruct(ctorType.Decl); + for (int i = 0; i < ctorType.Arguments.Length; ++i) { + VCExpr! newInnerTerm = Gen.Function(repr.Dtors[i], innerTerm); + TypeVarExtractors(var, ctorType.Arguments[i], newInnerTerm, extractors); + } + } + } else if (completeType.IsMap) { + TypeVarExtractors(var, MapTypeAbstracter.AbstractMapType(completeType.AsMap), + innerTerm, extractors); + } else { + System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + completeType); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Symbols for representing functions + + // Globally defined functions + private readonly IDictionary! Typed2UntypedFunctions; + + // distinguish between implicit and explicit type parameters + internal static void SeparateTypeParams(List! valueArgumentTypes, + TypeVariableSeq! allTypeParams, + out List! implicitParams, + out List! explicitParams) { + TypeVariableSeq! varsInInParamTypes = new TypeVariableSeq (); + foreach (Type! t in valueArgumentTypes) + varsInInParamTypes.AppendWithoutDups(t.FreeVariables); + + implicitParams = new List (allTypeParams.Length); + explicitParams = new List (allTypeParams.Length); + + foreach (TypeVariable! var in allTypeParams) { + if (varsInInParamTypes.Has(var)) + implicitParams.Add(var); + else + explicitParams.Add(var); + } + + implicitParams.TrimExcess(); + explicitParams.TrimExcess(); + } + + internal UntypedFunction Typed2Untyped(Function! fun) { + UntypedFunction res; + if (!Typed2UntypedFunctions.TryGetValue(fun, out res)) { + assert fun.OutParams.Length == 1; + + // if all of the parameters are int or bool, the function does + // not have to be changed + if (forall{Formal f in fun.InParams; UnchangedType(((!)f).TypedIdent.Type)} && + UnchangedType(((!)fun.OutParams[0]).TypedIdent.Type) && + fun.TypeParameters.Length == 0) { + res = new UntypedFunction(fun, new List (), new List ()); + } else { + List! argTypes = new List (); + foreach (Variable! v in fun.InParams) + argTypes.Add(v.TypedIdent.Type); + + List! implicitParams, explicitParams; + SeparateTypeParams(argTypes, fun.TypeParameters, out implicitParams, out explicitParams); + + Type[]! types = new Type [explicitParams.Count + fun.InParams.Length + 1]; + int i = 0; + for (int j = 0; j < explicitParams.Count; ++j) { + types[i] = T; + i = i + 1; + } + for (int j = 0; j < fun.InParams.Length; ++i, ++j) + types[i] = TypeAfterErasure(((!)fun.InParams[j]).TypedIdent.Type); + types[types.Length - 1] = TypeAfterErasure(((!)fun.OutParams[0]).TypedIdent.Type); + + Function! untypedFun = HelperFuns.BoogieFunction(fun.Name, types); + untypedFun.Attributes = fun.Attributes; + res = new UntypedFunction(untypedFun, implicitParams, explicitParams); + if (U.Equals(types[types.Length - 1])) + AddTypeAxiom(GenFunctionAxiom(res, fun)); + } + + Typed2UntypedFunctions.Add(fun, res); + } + return res; + } + + private VCExpr! GenFunctionAxiom(UntypedFunction fun, Function! originalFun) { + List! originalInTypes = new List (originalFun.InParams.Length); + foreach (Formal! f in originalFun.InParams) + originalInTypes.Add(f.TypedIdent.Type); + + return GenFunctionAxiom(fun.Fun, fun.ImplicitTypeParams, fun.ExplicitTypeParams, + originalInTypes, + ((!)originalFun.OutParams[0]).TypedIdent.Type); + } + + internal VCExpr! GenFunctionAxiom(Function! fun, + List! implicitTypeParams, + List! explicitTypeParams, + List! originalInTypes, + Type! originalResultType) + requires originalInTypes.Count + explicitTypeParams.Count == fun.InParams.Length; + { + if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) { + return VCExpressionGenerator.True; + } + + List! typedInputVars = new List(originalInTypes.Count); + int i = 0; + foreach (Type! t in originalInTypes) { + typedInputVars.Add(Gen.Variable("arg" + i, t)); + i = i + 1; + } + + VariableBindings! bindings = new VariableBindings (); + + // type parameters that have to be given explicitly are replaced + // with universally quantified type variables + List! boundVars = new List (explicitTypeParams.Count + typedInputVars.Count); + foreach (TypeVariable! var in explicitTypeParams) { + VCExprVar! newVar = Gen.Variable(var.Name, T); + boundVars.Add(newVar); + bindings.TypeVariableBindings.Add(var, newVar); + } + + // bound term variables are replaced with bound term variables typed in + // a simpler way + foreach (VCExprVar! var in typedInputVars) { + Type! newType = TypeAfterErasure(var.Type); + VCExprVar! newVar = Gen.Variable(var.Name, newType); + boundVars.Add(newVar); + bindings.VCExprVarBindings.Add(var, newVar); + } + + List typeVarBindings = + GenTypeParamBindings(implicitTypeParams, typedInputVars, bindings, true); + + VCExpr! funApp = Gen.Function(fun, HelperFuns.ToVCExprList(boundVars)); + VCExpr! conclusion = Gen.Eq(TypeOf(funApp), + Type2Term(originalResultType, bindings.TypeVariableBindings)); + VCExpr conclusionWithPremisses = + // leave out antecedents of function type axioms ... they don't appear necessary, + // because a function can always be extended to all U-values (right?) +// AddTypePremisses(typeVarBindings, typePremisses, true, conclusion); + Gen.Let(typeVarBindings, conclusion); + + if (boundVars.Count > 0) { + List triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(funApp))); + return Gen.Forall(boundVars, triggers, "funType:" + fun.Name, conclusionWithPremisses); + } else { + return conclusionWithPremisses; + } + } + + //////////////////////////////////////////////////////////////////////////// + + protected override void AddVarTypeAxiom(VCExprVar! var, Type! originalType) { + if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) return; + AddTypeAxiom(GenVarTypeAxiom(var, originalType, + // we don't have any bindings available + new Dictionary ())); + } + + public VCExpr! GenVarTypeAxiom(VCExprVar! var, Type! originalType, + IDictionary! varMapping) { + if (!var.Type.Equals(originalType)) { + VCExpr! typeRepr = Type2Term(originalType, varMapping); + return Gen.Eq(TypeOf(var), typeRepr); + } + return VCExpressionGenerator.True; + } + } + + ///////////////////////////////////////////////////////////////////////////// + + internal class MapTypeAbstractionBuilderPremisses : MapTypeAbstractionBuilder { + + private readonly TypeAxiomBuilderPremisses! AxBuilderPremisses; + + internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses! axBuilder, + VCExpressionGenerator! gen) { + base(axBuilder, gen); + this.AxBuilderPremisses = axBuilder; + } + + // constructor for cloning + internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses! axBuilder, + VCExpressionGenerator! gen, + MapTypeAbstractionBuilderPremisses! builder) { + base(axBuilder, gen, builder); + this.AxBuilderPremisses = axBuilder; + } + + //////////////////////////////////////////////////////////////////////////// + + // Determine the type parameters of a map type that have to be + // given explicitly when applying the select function (the + // parameters that only occur in the result type of the + // map). These parameters are given as a list of indexes sorted in + // ascending order; the index i refers to the i'th bound variable + // in a type [...]... + public List! ExplicitSelectTypeParams(MapType! type) { + List res; + if (!explicitSelectTypeParamsCache.TryGetValue(type, out res)) { + List! explicitParams, implicitParams; + TypeAxiomBuilderPremisses.SeparateTypeParams(type.Arguments.ToList(), + type.TypeParameters, + out implicitParams, + out explicitParams); + res = new List (explicitParams.Count); + foreach (TypeVariable! var in explicitParams) + res.Add(type.TypeParameters.IndexOf(var)); + explicitSelectTypeParamsCache.Add(type, res); + } + return (!)res; + } + + private IDictionary!>! explicitSelectTypeParamsCache = + new Dictionary!> (); + + //////////////////////////////////////////////////////////////////////////// + + protected override void GenSelectStoreFunctions(MapType! abstractedType, + TypeCtorDecl! synonym, + out Function! select, + out Function! store) { + Type! mapTypeSynonym; + List! typeParams; + List! originalInTypes; + GenTypeAxiomParams(abstractedType, synonym, out mapTypeSynonym, + out typeParams, out originalInTypes); + + // select + List! explicitSelectParams, implicitSelectParams; + select = CreateAccessFun(typeParams, originalInTypes, + abstractedType.Result, synonym.Name + "Select", + out implicitSelectParams, out explicitSelectParams); + + // store, which gets one further argument: the assigned rhs + originalInTypes.Add(abstractedType.Result); + + List! explicitStoreParams, implicitStoreParams; + store = CreateAccessFun(typeParams, originalInTypes, + mapTypeSynonym, synonym.Name + "Store", + out implicitStoreParams, out explicitStoreParams); + + // the store function does not have any explicit type parameters + assert explicitStoreParams.Count == 0; + + if (CommandLineOptions.Clo.UseArrayTheory) { + select.AddAttribute("builtin", "select"); + store.AddAttribute("builtin", "store"); + } else { + AxBuilder.AddTypeAxiom(GenMapAxiom0(select, store, + abstractedType.Result, + implicitSelectParams, explicitSelectParams, + originalInTypes)); + AxBuilder.AddTypeAxiom(GenMapAxiom1(select, store, + abstractedType.Result, + explicitSelectParams)); + } + } + + protected void GenTypeAxiomParams(MapType! abstractedType, TypeCtorDecl! synonymDecl, + out Type! mapTypeSynonym, + out List! typeParams, + out List! originalIndexTypes) { + typeParams = new List (abstractedType.TypeParameters.Length + abstractedType.FreeVariables.Length); + typeParams.AddRange(abstractedType.TypeParameters.ToList()); + typeParams.AddRange(abstractedType.FreeVariables.ToList()); + + originalIndexTypes = new List (abstractedType.Arguments.Length + 1); + TypeSeq! mapTypeParams = new TypeSeq (); + foreach (TypeVariable! var in abstractedType.FreeVariables) + mapTypeParams.Add(var); + + if (CommandLineOptions.Clo.UseArrayTheory) + mapTypeSynonym = abstractedType; + else + mapTypeSynonym = new CtorType (Token.NoToken, synonymDecl, mapTypeParams); + + originalIndexTypes.Add(mapTypeSynonym); + originalIndexTypes.AddRange(abstractedType.Arguments.ToList()); + } + + // method to actually create the select or store function + private Function! CreateAccessFun(List! originalTypeParams, + List! originalInTypes, + Type! originalResult, + string! name, + out List! implicitTypeParams, out List! explicitTypeParams) { + // select and store are basically handled like normal functions: the type + // parameters are split into the implicit parameters, and into the parameters + // that have to be given explicitly + TypeAxiomBuilderPremisses.SeparateTypeParams(originalInTypes, + HelperFuns.ToSeq(originalTypeParams), + out implicitTypeParams, + out explicitTypeParams); + + Type[]! ioTypes = new Type [explicitTypeParams.Count + originalInTypes.Count + 1]; + int i = 0; + for (; i < explicitTypeParams.Count; ++i) + ioTypes[i] = AxBuilder.T; + foreach (Type! type in originalInTypes) + { + if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(type)) + ioTypes[i] = type; + else + ioTypes[i] = AxBuilder.U; + i++; + } + if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(originalResult)) + ioTypes[i] = originalResult; + else + ioTypes[i] = AxBuilder.U; + + Function! res = HelperFuns.BoogieFunction(name, ioTypes); + + if (AxBuilder.U.Equals(ioTypes[i])) + { + AxBuilder.AddTypeAxiom( + AxBuilderPremisses.GenFunctionAxiom(res, + implicitTypeParams, explicitTypeParams, + originalInTypes, originalResult)); + } + return res; + } + + /////////////////////////////////////////////////////////////////////////// + // The normal axioms of the theory of arrays (without extensionality) + + private VCExpr! Select(Function! select, + // in general, the select function has to + // receive explicit type parameters (which + // are here already represented as VCExpr + // of type T) + List! typeParams, + VCExpr! map, + List! indexes) { + List! selectArgs = new List (typeParams.Count + indexes.Count + 1); + selectArgs.AddRange(typeParams); + selectArgs.Add(map); + selectArgs.AddRange(HelperFuns.ToVCExprList(indexes)); + return Gen.Function(select, selectArgs); + } + + private VCExpr! Store(Function! store, + VCExpr! map, + List! indexes, + VCExpr! val) { + List! storeArgs = new List (indexes.Count + 2); + storeArgs.Add(map); + storeArgs.AddRange(HelperFuns.ToVCExprList(indexes)); + storeArgs.Add(val); + return Gen.Function(store, storeArgs); + } + + /// + /// Generate: + /// (forall m, indexes, val :: + /// type(val) == T ==> + /// select(store(m, indexes, val), indexes) == val) + /// where the quantifier body is also enclosed in a let that defines portions of T, if needed. + /// + private VCExpr! GenMapAxiom0(Function! select, Function! store, + Type! mapResult, + List! implicitTypeParamsSelect, List! explicitTypeParamsSelect, + List! originalInTypes) + { + int arity = store.InParams.Length - 2; + List inParams = new List(); + List quantifiedVars = new List(store.InParams.Length); + VariableBindings bindings = new VariableBindings(); + + // bound variable: m + VCExprVar typedM = Gen.Variable("m", originalInTypes[0]); + VCExprVar m = Gen.Variable("m", AxBuilder.U); + inParams.Add(typedM); + quantifiedVars.Add(m); + bindings.VCExprVarBindings.Add(typedM, m); + + // bound variables: indexes + List origIndexTypes = new List(arity); + List indexTypes = new List(arity); + for (int i = 1; i < store.InParams.Length-1; i++) { + origIndexTypes.Add(originalInTypes[i]); + indexTypes.Add(((!)store.InParams[i]).TypedIdent.Type); + } + assert arity == indexTypes.Count; + List typedArgs = HelperFuns.VarVector("arg", origIndexTypes, Gen); + List indexes = HelperFuns.VarVector("x", indexTypes, Gen); + assert typedArgs.Count == indexes.Count; + inParams.AddRange(typedArgs); + quantifiedVars.AddRange(indexes); + for (int i = 0; i < arity; i++) { + bindings.VCExprVarBindings.Add(typedArgs[i], indexes[i]); + } + + // bound variable: val + VCExprVar typedVal = Gen.Variable("val", mapResult); + VCExprVar val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); + quantifiedVars.Add(val); + bindings.VCExprVarBindings.Add(typedVal, val); + + // add all type parameters into bindings + foreach (TypeVariable tp in implicitTypeParamsSelect) { + VCExprVar tVar = Gen.Variable(tp.Name, AxBuilderPremisses.T); + bindings.TypeVariableBindings.Add(tp, tVar); + } + List typeParams = new List(explicitTypeParamsSelect.Count); + foreach (TypeVariable tp in explicitTypeParamsSelect) { + VCExprVar tVar = Gen.Variable(tp.Name, AxBuilderPremisses.T); + bindings.TypeVariableBindings.Add(tp, tVar); + // ... and record these explicit type-parameter arguments in typeParams + typeParams.Add(tVar); + } + + VCExpr! storeExpr = Store(store, m, indexes, val); + VCExpr! selectExpr = Select(select, typeParams, storeExpr, indexes); + + // Create let-binding definitions for all type parameters. + // The implicit ones can be phrased in terms of the types of the ordinary in-parameters, and + // we want to make sure that they don't get phrased in terms of the out-parameter, so we pass + // in inParams here. + List letBindings_Implicit = + AxBuilderPremisses.GenTypeParamBindings(implicitTypeParamsSelect, inParams, bindings, false); + // The explicit ones, by definition, can only be phrased in terms of the result, so we pass + // in List(typedVal) here. + List letBindings_Explicit = + AxBuilderPremisses.GenTypeParamBindings(explicitTypeParamsSelect, HelperFuns.ToList(typedVal), bindings, false); + + // generate: select(store(m, indices, val)) == val + VCExpr! eq = Gen.Eq(selectExpr, val); + // generate: type(val) == T, where T is the type of val + VCExpr! ante = Gen.Eq( + AxBuilderPremisses.TypeOf(val), + AxBuilderPremisses.Type2Term(mapResult, bindings.TypeVariableBindings)); + VCExpr body; + if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None || + !AxBuilder.U.Equals(((!)select.OutParams[0]).TypedIdent.Type)) + { + body = Gen.Let(letBindings_Explicit, eq); + } else { + body = Gen.Let(letBindings_Implicit, Gen.Let(letBindings_Explicit, Gen.ImpliesSimp(ante, eq))); + } + return Gen.Forall(quantifiedVars, new List(), "mapAx0:" + select.Name, body); + } + + private VCExpr! GenMapAxiom1(Function! select, Function! store, + Type! mapResult, + List! explicitSelectParams) { + int arity = store.InParams.Length - 2; + + List indexTypes = new List(); + for (int i = 1; i < store.InParams.Length-1; i++) + { + indexTypes.Add(((!)store.InParams[i]).TypedIdent.Type); + } + assert indexTypes.Count == arity; + + List! indexes0 = HelperFuns.VarVector("x", indexTypes, Gen); + List! indexes1 = HelperFuns.VarVector("y", indexTypes, Gen); + VCExprVar! m = Gen.Variable("m", AxBuilder.U); + VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); + + // extract the explicit type parameters from the actual result type ... + VCExprVar! typedVal = Gen.Variable("val", mapResult); + VariableBindings! bindings = new VariableBindings (); + bindings.VCExprVarBindings.Add(typedVal, val); + + List! letBindings = + AxBuilderPremisses.GenTypeParamBindings(explicitSelectParams, + HelperFuns.ToList(typedVal), + bindings, true); + + // ... and quantify the introduced term variables for type + // parameters universally + List! typeParams = new List (explicitSelectParams.Count); + List! typeParamsExpr = new List (explicitSelectParams.Count); + foreach (TypeVariable! var in explicitSelectParams) { + VCExprVar! newVar = (VCExprVar)bindings.TypeVariableBindings[var]; + typeParams.Add(newVar); + typeParamsExpr.Add(newVar); + } + + VCExpr! storeExpr = Store(store, m, indexes0, val); + VCExpr! selectWithoutStoreExpr = Select(select, typeParamsExpr, m, indexes1); + VCExpr! selectExpr = Select(select, typeParamsExpr, storeExpr, indexes1); + + VCExpr! selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr); + + List! quantifiedVars = new List (indexes0.Count + indexes1.Count + 2); + quantifiedVars.Add(val); + quantifiedVars.Add(m); + quantifiedVars.AddRange(indexes0); + quantifiedVars.AddRange(indexes1); + quantifiedVars.AddRange(typeParams); + + List! triggers = new List (); + + VCExpr! axiom = VCExpressionGenerator.True; + + // first non-interference criterium: the queried location is + // different from the assigned location + for (int i = 0; i < arity; ++i) { + VCExpr! indexesEq = Gen.Eq(indexes0[i], indexes1[i]); + VCExpr! matrix = Gen.Or(indexesEq, selectEq); + VCExpr! conjunct = Gen.Forall(quantifiedVars, triggers, + "mapAx1:" + select.Name + ":" + i, matrix); + axiom = Gen.AndSimp(axiom, conjunct); + } + + // second non-interference criterion: the queried type is + // different from the assigned type + VCExpr! typesEq = VCExpressionGenerator.True; + foreach (VCExprLetBinding! b in letBindings) + typesEq = Gen.AndSimp(typesEq, Gen.Eq(b.V, b.E)); + VCExpr! matrix2 = Gen.Or(typesEq, selectEq); + VCExpr! conjunct2 = Gen.Forall(quantifiedVars, triggers, + "mapAx2:" + select.Name, matrix2); + axiom = Gen.AndSimp(axiom, conjunct2); + + return axiom; + } + + } + + ///////////////////////////////////////////////////////////////////////////// + + public class TypeEraserPremisses : TypeEraser { + + private readonly TypeAxiomBuilderPremisses! AxBuilderPremisses; + + private OpTypeEraser OpEraserAttr = null; + protected override OpTypeEraser! OpEraser { get { + if (OpEraserAttr == null) + OpEraserAttr = new OpTypeEraserPremisses(this, AxBuilderPremisses, Gen); + return OpEraserAttr; + } } + + public TypeEraserPremisses(TypeAxiomBuilderPremisses! axBuilder, + VCExpressionGenerator! gen) { + base(axBuilder, gen); + this.AxBuilderPremisses = axBuilder; + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr! Visit(VCExprQuantifier! node, + VariableBindings! oldBindings) { + VariableBindings bindings = oldBindings.Clone(); + + // determine the bound vars that actually occur in the body or + // in any of the triggers (if some variables do not occur, we + // need to take special care of type parameters that only occur + // in the types of such variables) + FreeVariableCollector coll = new FreeVariableCollector (); + coll.Collect(node.Body); + foreach (VCTrigger trigger in node.Triggers) { + if (trigger.Pos) + foreach (VCExpr! e in trigger.Exprs) + coll.Collect(e); + } + + List occurringVars = new List (node.BoundVars.Count); + foreach (VCExprVar var in node.BoundVars) + if (coll.FreeTermVars.ContainsKey(var)) + occurringVars.Add(var); + + occurringVars.TrimExcess(); + + // bound term variables are replaced with bound term variables typed in + // a simpler way + List! newBoundVars = + BoundVarsAfterErasure(occurringVars, bindings); + VCExpr! newNode = HandleQuantifier(node, occurringVars, + newBoundVars, bindings); + + if (!(newNode is VCExprQuantifier) || !IsUniversalQuantifier(node)) + return newNode; + + VariableBindings! bindings2; + if (!RedoQuantifier(node, (VCExprQuantifier)newNode, occurringVars, oldBindings, + out bindings2, out newBoundVars)) + return newNode; + + return HandleQuantifier(node, occurringVars, + newBoundVars, bindings2); + } + + private VCExpr! GenTypePremisses(List! oldBoundVars, + List! newBoundVars, + IDictionary! + typeVarTranslation, + List! typeVarBindings, + out List! triggers) { + // build a substitution of the type variables that it can be checked + // whether type premisses are trivial + VCExprSubstitution! typeParamSubstitution = new VCExprSubstitution (); + foreach (VCExprLetBinding! binding in typeVarBindings) + typeParamSubstitution[binding.V] = binding.E; + SubstitutingVCExprVisitor! substituter = new SubstitutingVCExprVisitor (Gen); + + List! typePremisses = new List (newBoundVars.Count); + triggers = new List (newBoundVars.Count); + + for (int i = 0; i < newBoundVars.Count; ++i) { + VCExprVar! oldVar = oldBoundVars[i]; + VCExprVar! newVar = newBoundVars[i]; + + VCExpr! typePremiss = + AxBuilderPremisses.GenVarTypeAxiom(newVar, oldVar.Type, + typeVarTranslation); + + if (!IsTriviallyTrue(substituter.Mutate(typePremiss, + typeParamSubstitution))) { + typePremisses.Add(typePremiss); + // generate a negative trigger for the variable occurrence + // in the type premiss + triggers.Add(Gen.Trigger(false, + HelperFuns.ToList(AxBuilderPremisses.TypeOf(newVar)))); + } + } + + typePremisses.TrimExcess(); + triggers.TrimExcess(); + + return Gen.NAry(VCExpressionGenerator.AndOp, typePremisses); + } + + // these optimisations should maybe be moved into a separate + // visitor (peep-hole optimisations) + private bool IsTriviallyTrue(VCExpr! expr) { + if (expr.Equals(VCExpressionGenerator.True)) + return true; + + if (expr is VCExprNAry) { + VCExprNAry! naryExpr = (VCExprNAry)expr; + if (naryExpr.Op.Equals(VCExpressionGenerator.EqOp) && + naryExpr[0].Equals(naryExpr[1])) + return true; + } + + return false; + } + + private VCExpr! HandleQuantifier(VCExprQuantifier! node, + List! occurringVars, + List! newBoundVars, + VariableBindings! bindings) { + List! typeVarBindings = + AxBuilderPremisses.GenTypeParamBindings(node.TypeParameters, occurringVars, bindings, true); + + // Check whether some of the type parameters could not be + // determined from the bound variable types. In this case, we + // quantify explicitly over these variables + if (typeVarBindings.Count < node.TypeParameters.Count) { + foreach (TypeVariable! var in node.TypeParameters) { + if (!exists{VCExprLetBinding! b in typeVarBindings; b.V.Equals(var)}) + newBoundVars.Add((VCExprVar)bindings.TypeVariableBindings[var]); + } + } + + // the lists of old and new bound variables for which type + // antecedents are to be generated + List! varsWithTypeSpecs = new List (); + List! newVarsWithTypeSpecs = new List (); + if (!IsUniversalQuantifier(node) || + CommandLineOptions.Clo.TypeEncodingMethod + == CommandLineOptions.TypeEncoding.Predicates) { + foreach (VCExprVar! oldVar in occurringVars) { + varsWithTypeSpecs.Add(oldVar); + newVarsWithTypeSpecs.Add(bindings.VCExprVarBindings[oldVar]); + } + } // else, no type antecedents are created for any variables + + List! furtherTriggers; + VCExpr! typePremisses = + GenTypePremisses(varsWithTypeSpecs, newVarsWithTypeSpecs, + bindings.TypeVariableBindings, + typeVarBindings, out furtherTriggers); + + List! newTriggers = MutateTriggers(node.Triggers, bindings); + newTriggers.AddRange(furtherTriggers); + newTriggers = AddLets2Triggers(newTriggers, typeVarBindings); + + VCExpr! newBody = Mutate(node.Body, bindings); + + // assemble the new quantified formula + + if (CommandLineOptions.Clo.TypeEncodingMethod + == CommandLineOptions.TypeEncoding.None) { + typePremisses = VCExpressionGenerator.True; + } + + VCExpr! bodyWithPremisses = + AxBuilderPremisses.AddTypePremisses(typeVarBindings, typePremisses, + node.Quan == Quantifier.ALL, + AxBuilder.Cast(newBody, Type.Bool)); + + if (newBoundVars.Count == 0) // might happen that no bound variables are left + return bodyWithPremisses; + + foreach(VCExprVar! v in newBoundVars) { + if (v.Type == AxBuilderPremisses.U) { + newTriggers.Add(Gen.Trigger(false, AxBuilderPremisses.Cast(v, Type.Int))); + newTriggers.Add(Gen.Trigger(false, AxBuilderPremisses.Cast(v, Type.Bool))); + } + } + + return Gen.Quantify(node.Quan, new List (), newBoundVars, + newTriggers, node.Infos, bodyWithPremisses); + } + + // check whether we need to add let-binders for any of the type + // parameters to the triggers (otherwise, the triggers will + // contain unbound/dangling variables for such parameters) + private List! AddLets2Triggers(List! triggers, + List! typeVarBindings) { + List! triggersWithLets = new List (triggers.Count); + + foreach (VCTrigger! t in triggers) { + List! exprsWithLets = new List (t.Exprs.Count); + + bool changed = false; + foreach (VCExpr! e in t.Exprs) { + Dictionary! freeVars = + FreeVariableCollector.FreeTermVariables(e); + + if (exists{VCExprLetBinding! b in typeVarBindings; + freeVars.ContainsKey(b.V)}) { + exprsWithLets.Add(Gen.Let(typeVarBindings, e)); + changed = true; + } else { + exprsWithLets.Add(e); + } + } + + if (changed) + triggersWithLets.Add(Gen.Trigger(t.Pos, exprsWithLets)); + else + triggersWithLets.Add(t); + } + + return triggersWithLets; + } + + } + + ////////////////////////////////////////////////////////////////////////////// + + public class OpTypeEraserPremisses : OpTypeEraser { + + private TypeAxiomBuilderPremisses! AxBuilderPremisses; + + public OpTypeEraserPremisses(TypeEraserPremisses! eraser, + TypeAxiomBuilderPremisses! axBuilder, + VCExpressionGenerator! gen) { + base(eraser, axBuilder, gen); + this.AxBuilderPremisses = axBuilder; + } + + private VCExpr! HandleFunctionOp(Function! newFun, + List! typeArgs, + IEnumerable! oldArgs, + VariableBindings! bindings) { + // UGLY: the code for tracking polarities should be factored out + int oldPolarity = Eraser.Polarity; + Eraser.Polarity = 0; + + List! newArgs = new List (typeArgs.Count); + + // translate the explicit type arguments + foreach (Type! t in typeArgs) + newArgs.Add(AxBuilder.Type2Term(t, bindings.TypeVariableBindings)); + + // recursively translate the value arguments + foreach (VCExpr! arg in oldArgs) { + Type! newType = ((!)newFun.InParams[newArgs.Count]).TypedIdent.Type; + newArgs.Add(AxBuilder.Cast(Eraser.Mutate(arg, bindings), newType)); + } + + Eraser.Polarity = oldPolarity; + return Gen.Function(newFun, newArgs); + } + + public override VCExpr! VisitSelectOp (VCExprNAry! node, + VariableBindings! bindings) { + MapType! mapType = node[0].Type.AsMap; + TypeSeq! instantiations; // not used + Function! select = + AxBuilder.MapTypeAbstracter.Select(mapType, out instantiations); + + List! explicitTypeParams = + AxBuilderPremisses.MapTypeAbstracterPremisses + .ExplicitSelectTypeParams(mapType); + assert select.InParams.Length == explicitTypeParams.Count + node.Arity; + + List! typeArgs = new List (explicitTypeParams.Count); + foreach (int i in explicitTypeParams) + typeArgs.Add(node.TypeArguments[i]); + return HandleFunctionOp(select, typeArgs, node, bindings); + } + + public override VCExpr! VisitStoreOp (VCExprNAry! node, + VariableBindings! bindings) { + TypeSeq! instantiations; // not used + Function! store = + AxBuilder.MapTypeAbstracter.Store(node[0].Type.AsMap, out instantiations); + return HandleFunctionOp(store, + // the store function never has explicit + // type parameters + new List (), + node, bindings); + } + + public override VCExpr! VisitBoogieFunctionOp (VCExprNAry! node, + VariableBindings! bindings) { + Function! oriFun = ((VCExprBoogieFunctionOp)node.Op).Func; + UntypedFunction untypedFun = AxBuilderPremisses.Typed2Untyped(oriFun); + assert untypedFun.Fun.InParams.Length == + untypedFun.ExplicitTypeParams.Count + node.Arity; + + List! typeArgs = + ExtractTypeArgs(node, + oriFun.TypeParameters, untypedFun.ExplicitTypeParams); + return HandleFunctionOp(untypedFun.Fun, typeArgs, node, bindings); + } + + private List! ExtractTypeArgs(VCExprNAry! node, + TypeVariableSeq! allTypeParams, + List! explicitTypeParams) { + List! res = new List (explicitTypeParams.Count); + foreach (TypeVariable! var in explicitTypeParams) + // this lookup could be optimised + res.Add(node.TypeArguments[allTypeParams.IndexOf(var)]); + return res; + } + } + + +} diff --git a/Source/VCExpr/TypeErasurePremisses.ssc b/Source/VCExpr/TypeErasurePremisses.ssc deleted file mode 100644 index 61144209..00000000 --- a/Source/VCExpr/TypeErasurePremisses.ssc +++ /dev/null @@ -1,1080 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -// Erasure of types using premisses (forall x :: type(x)=T ==> p(x)) - -namespace Microsoft.Boogie.TypeErasure -{ - using Microsoft.Boogie.VCExprAST; - - // When using type premisses, we can distinguish two kinds of type - // parameters of a function or map: parameters that occur in the - // formal argument types of the function are "implicit" because they - // can be inferred from the actual argument types; parameters that - // only occur in the result type of the function are "explicit" - // because they are not inferrable and have to be given to the - // function as additional arguments. - // - // The following structure is used to store the untyped version of a - // typed function, together with the lists of implicit and explicit - // type parameters (in the same order as they occur in the signature - // of the original function). - - internal struct UntypedFunction { - public readonly Function! Fun; - // type parameters that can be extracted from the value parameters - public readonly List! ImplicitTypeParams; - // type parameters that have to be given explicitly - public readonly List! ExplicitTypeParams; - - public UntypedFunction(Function! fun, - List! implicitTypeParams, - List! explicitTypeParams) { - Fun = fun; - ImplicitTypeParams = implicitTypeParams; - ExplicitTypeParams = explicitTypeParams; - } - } - - public class TypeAxiomBuilderPremisses : TypeAxiomBuilderIntBoolU { - - public TypeAxiomBuilderPremisses(VCExpressionGenerator! gen) { - base(gen); - TypeFunction = HelperFuns.BoogieFunction("dummy", Type.Int); - Typed2UntypedFunctions = new Dictionary (); - MapTypeAbstracterAttr = null; - } - - // constructor to allow cloning - [NotDelayed] - internal TypeAxiomBuilderPremisses(TypeAxiomBuilderPremisses! builder) { - TypeFunction = builder.TypeFunction; - Typed2UntypedFunctions = - new Dictionary (builder.Typed2UntypedFunctions); - base(builder); - - MapTypeAbstracterAttr = - builder.MapTypeAbstracterAttr == null ? - null : new MapTypeAbstractionBuilderPremisses(this, builder.Gen, - builder.MapTypeAbstracterAttr); - } - - public override Object! Clone() { - return new TypeAxiomBuilderPremisses(this); - } - - public override void Setup() { - TypeFunction = HelperFuns.BoogieFunction("type", U, T); - base.Setup(); - } - - //////////////////////////////////////////////////////////////////////////// - - // generate axioms of the kind "forall x:U. {Int2U(U2Int(x))} - // type(x)=int ==> Int2U(U2Int(x))==x" - protected override VCExpr! GenReverseCastAxiom(Function! castToU, Function! castFromU) { - List! triggers; - VCExprVar! var; - VCExpr! eq = GenReverseCastEq(castToU, castFromU, out var, out triggers); - VCExpr! premiss; - if (CommandLineOptions.Clo.TypeEncodingMethod - == CommandLineOptions.TypeEncoding.None) - premiss = VCExpressionGenerator.True; - else - premiss = GenVarTypeAxiom(var, ((!)castFromU.OutParams[0]).TypedIdent.Type, - // we don't have any bindings available - new Dictionary ()); - VCExpr! matrix = Gen.ImpliesSimp(premiss, eq); - return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, matrix); - } - - protected override VCExpr! GenCastTypeAxioms(Function! castToU, Function! castFromU) { - Type! fromType = ((!)castToU.InParams[0]).TypedIdent.Type; - return GenFunctionAxiom(castToU, new List (), new List (), - HelperFuns.ToList(fromType), fromType); - } - - private MapTypeAbstractionBuilderPremisses MapTypeAbstracterAttr; - - internal override MapTypeAbstractionBuilder! MapTypeAbstracter { get { - if (MapTypeAbstracterAttr == null) - MapTypeAbstracterAttr = new MapTypeAbstractionBuilderPremisses (this, Gen); - return MapTypeAbstracterAttr; - } } - - internal MapTypeAbstractionBuilderPremisses! MapTypeAbstracterPremisses { get { - return (MapTypeAbstractionBuilderPremisses)MapTypeAbstracter; - } } - - //////////////////////////////////////////////////////////////////////////// - - // function that maps individuals to their type - // the field is overwritten with its actual value in "Setup" - private Function! TypeFunction; - - public VCExpr! TypeOf(VCExpr! expr) { - return Gen.Function(TypeFunction, expr); - } - - /////////////////////////////////////////////////////////////////////////// - // Generate type premisses and type parameter bindings for quantifiers, functions, procedures - - // let-bindings to extract the instantiations of type parameters - public List! - GenTypeParamBindings(// the original bound variables and (implicit) type parameters - List! typeParams, List! oldBoundVars, - // VariableBindings to which the translation - // TypeVariable -> VCExprVar is added - VariableBindings! bindings, - bool addTypeVarsToBindings) { - // type variables are replaced with ordinary variables that are bound using a - // let-expression - if (addTypeVarsToBindings) { - foreach (TypeVariable! tvar in typeParams) - bindings.TypeVariableBindings.Add(tvar, Gen.Variable(tvar.Name, T)); - } - - // extract the values of type variables from the term variables - List! UtypedVars = new List (oldBoundVars.Count); - List! originalTypes = new List (oldBoundVars.Count); - foreach (VCExprVar var in oldBoundVars) { - VCExprVar! newVar = bindings.VCExprVarBindings[var]; - if (newVar.Type.Equals(U)) { - UtypedVars.Add(newVar); - originalTypes.Add(var.Type); - } - } - - UtypedVars.TrimExcess(); - originalTypes.TrimExcess(); - - return BestTypeVarExtractors(typeParams, originalTypes, UtypedVars, bindings); - } - - - public VCExpr! AddTypePremisses(List! typeVarBindings, - VCExpr! typePremisses, bool universal, - VCExpr! body) { - VCExpr! bodyWithPremisses; - if (universal) - bodyWithPremisses = Gen.ImpliesSimp(typePremisses, body); - else - bodyWithPremisses = Gen.AndSimp(typePremisses, body); - - return Gen.Let(typeVarBindings, bodyWithPremisses); - } - - - /////////////////////////////////////////////////////////////////////////// - // Extract the instantiations of type variables from the concrete types of - // term variables. E.g., for a function f(x : C a), we would extract the - // instantiation of "a" by looking at the concrete type of "x". - - public List! - BestTypeVarExtractors(List! vars, List! types, - List! concreteTypeSources, - VariableBindings! bindings) { - List! typeParamBindings = new List (); - foreach (TypeVariable! var in vars) { - VCExpr extractor = BestTypeVarExtractor(var, types, concreteTypeSources); - if (extractor != null) - typeParamBindings.Add( - Gen.LetBinding((VCExprVar)bindings.TypeVariableBindings[var], - extractor)); - } - return typeParamBindings; - } - - private VCExpr BestTypeVarExtractor(TypeVariable! var, List! types, - List! concreteTypeSources) { - List allExtractors = TypeVarExtractors(var, types, concreteTypeSources); - if (allExtractors.Count == 0) - return null; - - VCExpr bestExtractor = allExtractors[0]; - int bestExtractorSize = SizeComputingVisitor.ComputeSize(bestExtractor); - for (int i = 1; i < allExtractors.Count; ++i) { - int newSize = SizeComputingVisitor.ComputeSize(allExtractors[i]); - if (newSize < bestExtractorSize) { - bestExtractor = allExtractors[i]; - bestExtractorSize = newSize; - } - } - - return bestExtractor; - } - - private List! TypeVarExtractors(TypeVariable! var, List! types, - List! concreteTypeSources) - requires types.Count == concreteTypeSources.Count; { - List! res = new List(); - for (int i = 0; i < types.Count; ++i) - TypeVarExtractors(var, types[i], TypeOf(concreteTypeSources[i]), res); - - return res; - } - - private void TypeVarExtractors(TypeVariable! var, Type! completeType, - VCExpr! innerTerm, List! extractors) { - if (completeType.IsVariable) { - if (var.Equals(completeType)) { - extractors.Add(innerTerm); - } // else nothing - } else if (completeType.IsBasic) { - // nothing - } else if (completeType.IsCtor) { - CtorType! ctorType = completeType.AsCtor; - if (ctorType.Arguments.Length > 0) { - // otherwise there are no chances of extracting any - // instantiations from this type - TypeCtorRepr repr = GetTypeCtorReprStruct(ctorType.Decl); - for (int i = 0; i < ctorType.Arguments.Length; ++i) { - VCExpr! newInnerTerm = Gen.Function(repr.Dtors[i], innerTerm); - TypeVarExtractors(var, ctorType.Arguments[i], newInnerTerm, extractors); - } - } - } else if (completeType.IsMap) { - TypeVarExtractors(var, MapTypeAbstracter.AbstractMapType(completeType.AsMap), - innerTerm, extractors); - } else { - System.Diagnostics.Debug.Fail("Don't know how to handle this type: " + completeType); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Symbols for representing functions - - // Globally defined functions - private readonly IDictionary! Typed2UntypedFunctions; - - // distinguish between implicit and explicit type parameters - internal static void SeparateTypeParams(List! valueArgumentTypes, - TypeVariableSeq! allTypeParams, - out List! implicitParams, - out List! explicitParams) { - TypeVariableSeq! varsInInParamTypes = new TypeVariableSeq (); - foreach (Type! t in valueArgumentTypes) - varsInInParamTypes.AppendWithoutDups(t.FreeVariables); - - implicitParams = new List (allTypeParams.Length); - explicitParams = new List (allTypeParams.Length); - - foreach (TypeVariable! var in allTypeParams) { - if (varsInInParamTypes.Has(var)) - implicitParams.Add(var); - else - explicitParams.Add(var); - } - - implicitParams.TrimExcess(); - explicitParams.TrimExcess(); - } - - internal UntypedFunction Typed2Untyped(Function! fun) { - UntypedFunction res; - if (!Typed2UntypedFunctions.TryGetValue(fun, out res)) { - assert fun.OutParams.Length == 1; - - // if all of the parameters are int or bool, the function does - // not have to be changed - if (forall{Formal f in fun.InParams; UnchangedType(((!)f).TypedIdent.Type)} && - UnchangedType(((!)fun.OutParams[0]).TypedIdent.Type) && - fun.TypeParameters.Length == 0) { - res = new UntypedFunction(fun, new List (), new List ()); - } else { - List! argTypes = new List (); - foreach (Variable! v in fun.InParams) - argTypes.Add(v.TypedIdent.Type); - - List! implicitParams, explicitParams; - SeparateTypeParams(argTypes, fun.TypeParameters, out implicitParams, out explicitParams); - - Type[]! types = new Type [explicitParams.Count + fun.InParams.Length + 1]; - int i = 0; - for (int j = 0; j < explicitParams.Count; ++j) { - types[i] = T; - i = i + 1; - } - for (int j = 0; j < fun.InParams.Length; ++i, ++j) - types[i] = TypeAfterErasure(((!)fun.InParams[j]).TypedIdent.Type); - types[types.Length - 1] = TypeAfterErasure(((!)fun.OutParams[0]).TypedIdent.Type); - - Function! untypedFun = HelperFuns.BoogieFunction(fun.Name, types); - untypedFun.Attributes = fun.Attributes; - res = new UntypedFunction(untypedFun, implicitParams, explicitParams); - if (U.Equals(types[types.Length - 1])) - AddTypeAxiom(GenFunctionAxiom(res, fun)); - } - - Typed2UntypedFunctions.Add(fun, res); - } - return res; - } - - private VCExpr! GenFunctionAxiom(UntypedFunction fun, Function! originalFun) { - List! originalInTypes = new List (originalFun.InParams.Length); - foreach (Formal! f in originalFun.InParams) - originalInTypes.Add(f.TypedIdent.Type); - - return GenFunctionAxiom(fun.Fun, fun.ImplicitTypeParams, fun.ExplicitTypeParams, - originalInTypes, - ((!)originalFun.OutParams[0]).TypedIdent.Type); - } - - internal VCExpr! GenFunctionAxiom(Function! fun, - List! implicitTypeParams, - List! explicitTypeParams, - List! originalInTypes, - Type! originalResultType) - requires originalInTypes.Count + explicitTypeParams.Count == fun.InParams.Length; - { - if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) { - return VCExpressionGenerator.True; - } - - List! typedInputVars = new List(originalInTypes.Count); - int i = 0; - foreach (Type! t in originalInTypes) { - typedInputVars.Add(Gen.Variable("arg" + i, t)); - i = i + 1; - } - - VariableBindings! bindings = new VariableBindings (); - - // type parameters that have to be given explicitly are replaced - // with universally quantified type variables - List! boundVars = new List (explicitTypeParams.Count + typedInputVars.Count); - foreach (TypeVariable! var in explicitTypeParams) { - VCExprVar! newVar = Gen.Variable(var.Name, T); - boundVars.Add(newVar); - bindings.TypeVariableBindings.Add(var, newVar); - } - - // bound term variables are replaced with bound term variables typed in - // a simpler way - foreach (VCExprVar! var in typedInputVars) { - Type! newType = TypeAfterErasure(var.Type); - VCExprVar! newVar = Gen.Variable(var.Name, newType); - boundVars.Add(newVar); - bindings.VCExprVarBindings.Add(var, newVar); - } - - List typeVarBindings = - GenTypeParamBindings(implicitTypeParams, typedInputVars, bindings, true); - - VCExpr! funApp = Gen.Function(fun, HelperFuns.ToVCExprList(boundVars)); - VCExpr! conclusion = Gen.Eq(TypeOf(funApp), - Type2Term(originalResultType, bindings.TypeVariableBindings)); - VCExpr conclusionWithPremisses = - // leave out antecedents of function type axioms ... they don't appear necessary, - // because a function can always be extended to all U-values (right?) -// AddTypePremisses(typeVarBindings, typePremisses, true, conclusion); - Gen.Let(typeVarBindings, conclusion); - - if (boundVars.Count > 0) { - List triggers = HelperFuns.ToList(Gen.Trigger(true, HelperFuns.ToList(funApp))); - return Gen.Forall(boundVars, triggers, "funType:" + fun.Name, conclusionWithPremisses); - } else { - return conclusionWithPremisses; - } - } - - //////////////////////////////////////////////////////////////////////////// - - protected override void AddVarTypeAxiom(VCExprVar! var, Type! originalType) { - if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) return; - AddTypeAxiom(GenVarTypeAxiom(var, originalType, - // we don't have any bindings available - new Dictionary ())); - } - - public VCExpr! GenVarTypeAxiom(VCExprVar! var, Type! originalType, - IDictionary! varMapping) { - if (!var.Type.Equals(originalType)) { - VCExpr! typeRepr = Type2Term(originalType, varMapping); - return Gen.Eq(TypeOf(var), typeRepr); - } - return VCExpressionGenerator.True; - } - } - - ///////////////////////////////////////////////////////////////////////////// - - internal class MapTypeAbstractionBuilderPremisses : MapTypeAbstractionBuilder { - - private readonly TypeAxiomBuilderPremisses! AxBuilderPremisses; - - internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses! axBuilder, - VCExpressionGenerator! gen) { - base(axBuilder, gen); - this.AxBuilderPremisses = axBuilder; - } - - // constructor for cloning - internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses! axBuilder, - VCExpressionGenerator! gen, - MapTypeAbstractionBuilderPremisses! builder) { - base(axBuilder, gen, builder); - this.AxBuilderPremisses = axBuilder; - } - - //////////////////////////////////////////////////////////////////////////// - - // Determine the type parameters of a map type that have to be - // given explicitly when applying the select function (the - // parameters that only occur in the result type of the - // map). These parameters are given as a list of indexes sorted in - // ascending order; the index i refers to the i'th bound variable - // in a type [...]... - public List! ExplicitSelectTypeParams(MapType! type) { - List res; - if (!explicitSelectTypeParamsCache.TryGetValue(type, out res)) { - List! explicitParams, implicitParams; - TypeAxiomBuilderPremisses.SeparateTypeParams(type.Arguments.ToList(), - type.TypeParameters, - out implicitParams, - out explicitParams); - res = new List (explicitParams.Count); - foreach (TypeVariable! var in explicitParams) - res.Add(type.TypeParameters.IndexOf(var)); - explicitSelectTypeParamsCache.Add(type, res); - } - return (!)res; - } - - private IDictionary!>! explicitSelectTypeParamsCache = - new Dictionary!> (); - - //////////////////////////////////////////////////////////////////////////// - - protected override void GenSelectStoreFunctions(MapType! abstractedType, - TypeCtorDecl! synonym, - out Function! select, - out Function! store) { - Type! mapTypeSynonym; - List! typeParams; - List! originalInTypes; - GenTypeAxiomParams(abstractedType, synonym, out mapTypeSynonym, - out typeParams, out originalInTypes); - - // select - List! explicitSelectParams, implicitSelectParams; - select = CreateAccessFun(typeParams, originalInTypes, - abstractedType.Result, synonym.Name + "Select", - out implicitSelectParams, out explicitSelectParams); - - // store, which gets one further argument: the assigned rhs - originalInTypes.Add(abstractedType.Result); - - List! explicitStoreParams, implicitStoreParams; - store = CreateAccessFun(typeParams, originalInTypes, - mapTypeSynonym, synonym.Name + "Store", - out implicitStoreParams, out explicitStoreParams); - - // the store function does not have any explicit type parameters - assert explicitStoreParams.Count == 0; - - if (CommandLineOptions.Clo.UseArrayTheory) { - select.AddAttribute("builtin", "select"); - store.AddAttribute("builtin", "store"); - } else { - AxBuilder.AddTypeAxiom(GenMapAxiom0(select, store, - abstractedType.Result, - implicitSelectParams, explicitSelectParams, - originalInTypes)); - AxBuilder.AddTypeAxiom(GenMapAxiom1(select, store, - abstractedType.Result, - explicitSelectParams)); - } - } - - protected void GenTypeAxiomParams(MapType! abstractedType, TypeCtorDecl! synonymDecl, - out Type! mapTypeSynonym, - out List! typeParams, - out List! originalIndexTypes) { - typeParams = new List (abstractedType.TypeParameters.Length + abstractedType.FreeVariables.Length); - typeParams.AddRange(abstractedType.TypeParameters.ToList()); - typeParams.AddRange(abstractedType.FreeVariables.ToList()); - - originalIndexTypes = new List (abstractedType.Arguments.Length + 1); - TypeSeq! mapTypeParams = new TypeSeq (); - foreach (TypeVariable! var in abstractedType.FreeVariables) - mapTypeParams.Add(var); - - if (CommandLineOptions.Clo.UseArrayTheory) - mapTypeSynonym = abstractedType; - else - mapTypeSynonym = new CtorType (Token.NoToken, synonymDecl, mapTypeParams); - - originalIndexTypes.Add(mapTypeSynonym); - originalIndexTypes.AddRange(abstractedType.Arguments.ToList()); - } - - // method to actually create the select or store function - private Function! CreateAccessFun(List! originalTypeParams, - List! originalInTypes, - Type! originalResult, - string! name, - out List! implicitTypeParams, out List! explicitTypeParams) { - // select and store are basically handled like normal functions: the type - // parameters are split into the implicit parameters, and into the parameters - // that have to be given explicitly - TypeAxiomBuilderPremisses.SeparateTypeParams(originalInTypes, - HelperFuns.ToSeq(originalTypeParams), - out implicitTypeParams, - out explicitTypeParams); - - Type[]! ioTypes = new Type [explicitTypeParams.Count + originalInTypes.Count + 1]; - int i = 0; - for (; i < explicitTypeParams.Count; ++i) - ioTypes[i] = AxBuilder.T; - foreach (Type! type in originalInTypes) - { - if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(type)) - ioTypes[i] = type; - else - ioTypes[i] = AxBuilder.U; - i++; - } - if (CommandLineOptions.Clo.Monomorphize && AxBuilder.UnchangedType(originalResult)) - ioTypes[i] = originalResult; - else - ioTypes[i] = AxBuilder.U; - - Function! res = HelperFuns.BoogieFunction(name, ioTypes); - - if (AxBuilder.U.Equals(ioTypes[i])) - { - AxBuilder.AddTypeAxiom( - AxBuilderPremisses.GenFunctionAxiom(res, - implicitTypeParams, explicitTypeParams, - originalInTypes, originalResult)); - } - return res; - } - - /////////////////////////////////////////////////////////////////////////// - // The normal axioms of the theory of arrays (without extensionality) - - private VCExpr! Select(Function! select, - // in general, the select function has to - // receive explicit type parameters (which - // are here already represented as VCExpr - // of type T) - List! typeParams, - VCExpr! map, - List! indexes) { - List! selectArgs = new List (typeParams.Count + indexes.Count + 1); - selectArgs.AddRange(typeParams); - selectArgs.Add(map); - selectArgs.AddRange(HelperFuns.ToVCExprList(indexes)); - return Gen.Function(select, selectArgs); - } - - private VCExpr! Store(Function! store, - VCExpr! map, - List! indexes, - VCExpr! val) { - List! storeArgs = new List (indexes.Count + 2); - storeArgs.Add(map); - storeArgs.AddRange(HelperFuns.ToVCExprList(indexes)); - storeArgs.Add(val); - return Gen.Function(store, storeArgs); - } - - /// - /// Generate: - /// (forall m, indexes, val :: - /// type(val) == T ==> - /// select(store(m, indexes, val), indexes) == val) - /// where the quantifier body is also enclosed in a let that defines portions of T, if needed. - /// - private VCExpr! GenMapAxiom0(Function! select, Function! store, - Type! mapResult, - List! implicitTypeParamsSelect, List! explicitTypeParamsSelect, - List! originalInTypes) - { - int arity = store.InParams.Length - 2; - List inParams = new List(); - List quantifiedVars = new List(store.InParams.Length); - VariableBindings bindings = new VariableBindings(); - - // bound variable: m - VCExprVar typedM = Gen.Variable("m", originalInTypes[0]); - VCExprVar m = Gen.Variable("m", AxBuilder.U); - inParams.Add(typedM); - quantifiedVars.Add(m); - bindings.VCExprVarBindings.Add(typedM, m); - - // bound variables: indexes - List origIndexTypes = new List(arity); - List indexTypes = new List(arity); - for (int i = 1; i < store.InParams.Length-1; i++) { - origIndexTypes.Add(originalInTypes[i]); - indexTypes.Add(((!)store.InParams[i]).TypedIdent.Type); - } - assert arity == indexTypes.Count; - List typedArgs = HelperFuns.VarVector("arg", origIndexTypes, Gen); - List indexes = HelperFuns.VarVector("x", indexTypes, Gen); - assert typedArgs.Count == indexes.Count; - inParams.AddRange(typedArgs); - quantifiedVars.AddRange(indexes); - for (int i = 0; i < arity; i++) { - bindings.VCExprVarBindings.Add(typedArgs[i], indexes[i]); - } - - // bound variable: val - VCExprVar typedVal = Gen.Variable("val", mapResult); - VCExprVar val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); - quantifiedVars.Add(val); - bindings.VCExprVarBindings.Add(typedVal, val); - - // add all type parameters into bindings - foreach (TypeVariable tp in implicitTypeParamsSelect) { - VCExprVar tVar = Gen.Variable(tp.Name, AxBuilderPremisses.T); - bindings.TypeVariableBindings.Add(tp, tVar); - } - List typeParams = new List(explicitTypeParamsSelect.Count); - foreach (TypeVariable tp in explicitTypeParamsSelect) { - VCExprVar tVar = Gen.Variable(tp.Name, AxBuilderPremisses.T); - bindings.TypeVariableBindings.Add(tp, tVar); - // ... and record these explicit type-parameter arguments in typeParams - typeParams.Add(tVar); - } - - VCExpr! storeExpr = Store(store, m, indexes, val); - VCExpr! selectExpr = Select(select, typeParams, storeExpr, indexes); - - // Create let-binding definitions for all type parameters. - // The implicit ones can be phrased in terms of the types of the ordinary in-parameters, and - // we want to make sure that they don't get phrased in terms of the out-parameter, so we pass - // in inParams here. - List letBindings_Implicit = - AxBuilderPremisses.GenTypeParamBindings(implicitTypeParamsSelect, inParams, bindings, false); - // The explicit ones, by definition, can only be phrased in terms of the result, so we pass - // in List(typedVal) here. - List letBindings_Explicit = - AxBuilderPremisses.GenTypeParamBindings(explicitTypeParamsSelect, HelperFuns.ToList(typedVal), bindings, false); - - // generate: select(store(m, indices, val)) == val - VCExpr! eq = Gen.Eq(selectExpr, val); - // generate: type(val) == T, where T is the type of val - VCExpr! ante = Gen.Eq( - AxBuilderPremisses.TypeOf(val), - AxBuilderPremisses.Type2Term(mapResult, bindings.TypeVariableBindings)); - VCExpr body; - if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None || - !AxBuilder.U.Equals(((!)select.OutParams[0]).TypedIdent.Type)) - { - body = Gen.Let(letBindings_Explicit, eq); - } else { - body = Gen.Let(letBindings_Implicit, Gen.Let(letBindings_Explicit, Gen.ImpliesSimp(ante, eq))); - } - return Gen.Forall(quantifiedVars, new List(), "mapAx0:" + select.Name, body); - } - - private VCExpr! GenMapAxiom1(Function! select, Function! store, - Type! mapResult, - List! explicitSelectParams) { - int arity = store.InParams.Length - 2; - - List indexTypes = new List(); - for (int i = 1; i < store.InParams.Length-1; i++) - { - indexTypes.Add(((!)store.InParams[i]).TypedIdent.Type); - } - assert indexTypes.Count == arity; - - List! indexes0 = HelperFuns.VarVector("x", indexTypes, Gen); - List! indexes1 = HelperFuns.VarVector("y", indexTypes, Gen); - VCExprVar! m = Gen.Variable("m", AxBuilder.U); - VCExprVar! val = Gen.Variable("val", ((!)select.OutParams[0]).TypedIdent.Type); - - // extract the explicit type parameters from the actual result type ... - VCExprVar! typedVal = Gen.Variable("val", mapResult); - VariableBindings! bindings = new VariableBindings (); - bindings.VCExprVarBindings.Add(typedVal, val); - - List! letBindings = - AxBuilderPremisses.GenTypeParamBindings(explicitSelectParams, - HelperFuns.ToList(typedVal), - bindings, true); - - // ... and quantify the introduced term variables for type - // parameters universally - List! typeParams = new List (explicitSelectParams.Count); - List! typeParamsExpr = new List (explicitSelectParams.Count); - foreach (TypeVariable! var in explicitSelectParams) { - VCExprVar! newVar = (VCExprVar)bindings.TypeVariableBindings[var]; - typeParams.Add(newVar); - typeParamsExpr.Add(newVar); - } - - VCExpr! storeExpr = Store(store, m, indexes0, val); - VCExpr! selectWithoutStoreExpr = Select(select, typeParamsExpr, m, indexes1); - VCExpr! selectExpr = Select(select, typeParamsExpr, storeExpr, indexes1); - - VCExpr! selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr); - - List! quantifiedVars = new List (indexes0.Count + indexes1.Count + 2); - quantifiedVars.Add(val); - quantifiedVars.Add(m); - quantifiedVars.AddRange(indexes0); - quantifiedVars.AddRange(indexes1); - quantifiedVars.AddRange(typeParams); - - List! triggers = new List (); - - VCExpr! axiom = VCExpressionGenerator.True; - - // first non-interference criterium: the queried location is - // different from the assigned location - for (int i = 0; i < arity; ++i) { - VCExpr! indexesEq = Gen.Eq(indexes0[i], indexes1[i]); - VCExpr! matrix = Gen.Or(indexesEq, selectEq); - VCExpr! conjunct = Gen.Forall(quantifiedVars, triggers, - "mapAx1:" + select.Name + ":" + i, matrix); - axiom = Gen.AndSimp(axiom, conjunct); - } - - // second non-interference criterion: the queried type is - // different from the assigned type - VCExpr! typesEq = VCExpressionGenerator.True; - foreach (VCExprLetBinding! b in letBindings) - typesEq = Gen.AndSimp(typesEq, Gen.Eq(b.V, b.E)); - VCExpr! matrix2 = Gen.Or(typesEq, selectEq); - VCExpr! conjunct2 = Gen.Forall(quantifiedVars, triggers, - "mapAx2:" + select.Name, matrix2); - axiom = Gen.AndSimp(axiom, conjunct2); - - return axiom; - } - - } - - ///////////////////////////////////////////////////////////////////////////// - - public class TypeEraserPremisses : TypeEraser { - - private readonly TypeAxiomBuilderPremisses! AxBuilderPremisses; - - private OpTypeEraser OpEraserAttr = null; - protected override OpTypeEraser! OpEraser { get { - if (OpEraserAttr == null) - OpEraserAttr = new OpTypeEraserPremisses(this, AxBuilderPremisses, Gen); - return OpEraserAttr; - } } - - public TypeEraserPremisses(TypeAxiomBuilderPremisses! axBuilder, - VCExpressionGenerator! gen) { - base(axBuilder, gen); - this.AxBuilderPremisses = axBuilder; - } - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr! Visit(VCExprQuantifier! node, - VariableBindings! oldBindings) { - VariableBindings bindings = oldBindings.Clone(); - - // determine the bound vars that actually occur in the body or - // in any of the triggers (if some variables do not occur, we - // need to take special care of type parameters that only occur - // in the types of such variables) - FreeVariableCollector coll = new FreeVariableCollector (); - coll.Collect(node.Body); - foreach (VCTrigger trigger in node.Triggers) { - if (trigger.Pos) - foreach (VCExpr! e in trigger.Exprs) - coll.Collect(e); - } - - List occurringVars = new List (node.BoundVars.Count); - foreach (VCExprVar var in node.BoundVars) - if (coll.FreeTermVars.ContainsKey(var)) - occurringVars.Add(var); - - occurringVars.TrimExcess(); - - // bound term variables are replaced with bound term variables typed in - // a simpler way - List! newBoundVars = - BoundVarsAfterErasure(occurringVars, bindings); - VCExpr! newNode = HandleQuantifier(node, occurringVars, - newBoundVars, bindings); - - if (!(newNode is VCExprQuantifier) || !IsUniversalQuantifier(node)) - return newNode; - - VariableBindings! bindings2; - if (!RedoQuantifier(node, (VCExprQuantifier)newNode, occurringVars, oldBindings, - out bindings2, out newBoundVars)) - return newNode; - - return HandleQuantifier(node, occurringVars, - newBoundVars, bindings2); - } - - private VCExpr! GenTypePremisses(List! oldBoundVars, - List! newBoundVars, - IDictionary! - typeVarTranslation, - List! typeVarBindings, - out List! triggers) { - // build a substitution of the type variables that it can be checked - // whether type premisses are trivial - VCExprSubstitution! typeParamSubstitution = new VCExprSubstitution (); - foreach (VCExprLetBinding! binding in typeVarBindings) - typeParamSubstitution[binding.V] = binding.E; - SubstitutingVCExprVisitor! substituter = new SubstitutingVCExprVisitor (Gen); - - List! typePremisses = new List (newBoundVars.Count); - triggers = new List (newBoundVars.Count); - - for (int i = 0; i < newBoundVars.Count; ++i) { - VCExprVar! oldVar = oldBoundVars[i]; - VCExprVar! newVar = newBoundVars[i]; - - VCExpr! typePremiss = - AxBuilderPremisses.GenVarTypeAxiom(newVar, oldVar.Type, - typeVarTranslation); - - if (!IsTriviallyTrue(substituter.Mutate(typePremiss, - typeParamSubstitution))) { - typePremisses.Add(typePremiss); - // generate a negative trigger for the variable occurrence - // in the type premiss - triggers.Add(Gen.Trigger(false, - HelperFuns.ToList(AxBuilderPremisses.TypeOf(newVar)))); - } - } - - typePremisses.TrimExcess(); - triggers.TrimExcess(); - - return Gen.NAry(VCExpressionGenerator.AndOp, typePremisses); - } - - // these optimisations should maybe be moved into a separate - // visitor (peep-hole optimisations) - private bool IsTriviallyTrue(VCExpr! expr) { - if (expr.Equals(VCExpressionGenerator.True)) - return true; - - if (expr is VCExprNAry) { - VCExprNAry! naryExpr = (VCExprNAry)expr; - if (naryExpr.Op.Equals(VCExpressionGenerator.EqOp) && - naryExpr[0].Equals(naryExpr[1])) - return true; - } - - return false; - } - - private VCExpr! HandleQuantifier(VCExprQuantifier! node, - List! occurringVars, - List! newBoundVars, - VariableBindings! bindings) { - List! typeVarBindings = - AxBuilderPremisses.GenTypeParamBindings(node.TypeParameters, occurringVars, bindings, true); - - // Check whether some of the type parameters could not be - // determined from the bound variable types. In this case, we - // quantify explicitly over these variables - if (typeVarBindings.Count < node.TypeParameters.Count) { - foreach (TypeVariable! var in node.TypeParameters) { - if (!exists{VCExprLetBinding! b in typeVarBindings; b.V.Equals(var)}) - newBoundVars.Add((VCExprVar)bindings.TypeVariableBindings[var]); - } - } - - // the lists of old and new bound variables for which type - // antecedents are to be generated - List! varsWithTypeSpecs = new List (); - List! newVarsWithTypeSpecs = new List (); - if (!IsUniversalQuantifier(node) || - CommandLineOptions.Clo.TypeEncodingMethod - == CommandLineOptions.TypeEncoding.Predicates) { - foreach (VCExprVar! oldVar in occurringVars) { - varsWithTypeSpecs.Add(oldVar); - newVarsWithTypeSpecs.Add(bindings.VCExprVarBindings[oldVar]); - } - } // else, no type antecedents are created for any variables - - List! furtherTriggers; - VCExpr! typePremisses = - GenTypePremisses(varsWithTypeSpecs, newVarsWithTypeSpecs, - bindings.TypeVariableBindings, - typeVarBindings, out furtherTriggers); - - List! newTriggers = MutateTriggers(node.Triggers, bindings); - newTriggers.AddRange(furtherTriggers); - newTriggers = AddLets2Triggers(newTriggers, typeVarBindings); - - VCExpr! newBody = Mutate(node.Body, bindings); - - // assemble the new quantified formula - - if (CommandLineOptions.Clo.TypeEncodingMethod - == CommandLineOptions.TypeEncoding.None) { - typePremisses = VCExpressionGenerator.True; - } - - VCExpr! bodyWithPremisses = - AxBuilderPremisses.AddTypePremisses(typeVarBindings, typePremisses, - node.Quan == Quantifier.ALL, - AxBuilder.Cast(newBody, Type.Bool)); - - if (newBoundVars.Count == 0) // might happen that no bound variables are left - return bodyWithPremisses; - - foreach(VCExprVar! v in newBoundVars) { - if (v.Type == AxBuilderPremisses.U) { - newTriggers.Add(Gen.Trigger(false, AxBuilderPremisses.Cast(v, Type.Int))); - newTriggers.Add(Gen.Trigger(false, AxBuilderPremisses.Cast(v, Type.Bool))); - } - } - - return Gen.Quantify(node.Quan, new List (), newBoundVars, - newTriggers, node.Infos, bodyWithPremisses); - } - - // check whether we need to add let-binders for any of the type - // parameters to the triggers (otherwise, the triggers will - // contain unbound/dangling variables for such parameters) - private List! AddLets2Triggers(List! triggers, - List! typeVarBindings) { - List! triggersWithLets = new List (triggers.Count); - - foreach (VCTrigger! t in triggers) { - List! exprsWithLets = new List (t.Exprs.Count); - - bool changed = false; - foreach (VCExpr! e in t.Exprs) { - Dictionary! freeVars = - FreeVariableCollector.FreeTermVariables(e); - - if (exists{VCExprLetBinding! b in typeVarBindings; - freeVars.ContainsKey(b.V)}) { - exprsWithLets.Add(Gen.Let(typeVarBindings, e)); - changed = true; - } else { - exprsWithLets.Add(e); - } - } - - if (changed) - triggersWithLets.Add(Gen.Trigger(t.Pos, exprsWithLets)); - else - triggersWithLets.Add(t); - } - - return triggersWithLets; - } - - } - - ////////////////////////////////////////////////////////////////////////////// - - public class OpTypeEraserPremisses : OpTypeEraser { - - private TypeAxiomBuilderPremisses! AxBuilderPremisses; - - public OpTypeEraserPremisses(TypeEraserPremisses! eraser, - TypeAxiomBuilderPremisses! axBuilder, - VCExpressionGenerator! gen) { - base(eraser, axBuilder, gen); - this.AxBuilderPremisses = axBuilder; - } - - private VCExpr! HandleFunctionOp(Function! newFun, - List! typeArgs, - IEnumerable! oldArgs, - VariableBindings! bindings) { - // UGLY: the code for tracking polarities should be factored out - int oldPolarity = Eraser.Polarity; - Eraser.Polarity = 0; - - List! newArgs = new List (typeArgs.Count); - - // translate the explicit type arguments - foreach (Type! t in typeArgs) - newArgs.Add(AxBuilder.Type2Term(t, bindings.TypeVariableBindings)); - - // recursively translate the value arguments - foreach (VCExpr! arg in oldArgs) { - Type! newType = ((!)newFun.InParams[newArgs.Count]).TypedIdent.Type; - newArgs.Add(AxBuilder.Cast(Eraser.Mutate(arg, bindings), newType)); - } - - Eraser.Polarity = oldPolarity; - return Gen.Function(newFun, newArgs); - } - - public override VCExpr! VisitSelectOp (VCExprNAry! node, - VariableBindings! bindings) { - MapType! mapType = node[0].Type.AsMap; - TypeSeq! instantiations; // not used - Function! select = - AxBuilder.MapTypeAbstracter.Select(mapType, out instantiations); - - List! explicitTypeParams = - AxBuilderPremisses.MapTypeAbstracterPremisses - .ExplicitSelectTypeParams(mapType); - assert select.InParams.Length == explicitTypeParams.Count + node.Arity; - - List! typeArgs = new List (explicitTypeParams.Count); - foreach (int i in explicitTypeParams) - typeArgs.Add(node.TypeArguments[i]); - return HandleFunctionOp(select, typeArgs, node, bindings); - } - - public override VCExpr! VisitStoreOp (VCExprNAry! node, - VariableBindings! bindings) { - TypeSeq! instantiations; // not used - Function! store = - AxBuilder.MapTypeAbstracter.Store(node[0].Type.AsMap, out instantiations); - return HandleFunctionOp(store, - // the store function never has explicit - // type parameters - new List (), - node, bindings); - } - - public override VCExpr! VisitBoogieFunctionOp (VCExprNAry! node, - VariableBindings! bindings) { - Function! oriFun = ((VCExprBoogieFunctionOp)node.Op).Func; - UntypedFunction untypedFun = AxBuilderPremisses.Typed2Untyped(oriFun); - assert untypedFun.Fun.InParams.Length == - untypedFun.ExplicitTypeParams.Count + node.Arity; - - List! typeArgs = - ExtractTypeArgs(node, - oriFun.TypeParameters, untypedFun.ExplicitTypeParams); - return HandleFunctionOp(untypedFun.Fun, typeArgs, node, bindings); - } - - private List! ExtractTypeArgs(VCExprNAry! node, - TypeVariableSeq! allTypeParams, - List! explicitTypeParams) { - List! res = new List (explicitTypeParams.Count); - foreach (TypeVariable! var in explicitTypeParams) - // this lookup could be optimised - res.Add(node.TypeArguments[allTypeParams.IndexOf(var)]); - return res; - } - } - - -} diff --git a/Source/VCExpr/VCExpr.csproj b/Source/VCExpr/VCExpr.csproj new file mode 100644 index 00000000..53482aa5 --- /dev/null +++ b/Source/VCExpr/VCExpr.csproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/VCExpr/VCExpr.sscproj b/Source/VCExpr/VCExpr.sscproj deleted file mode 100644 index 53482aa5..00000000 --- a/Source/VCExpr/VCExpr.sscproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/VCExpr/VCExprAST.cs b/Source/VCExpr/VCExprAST.cs new file mode 100644 index 00000000..7e5b31f1 --- /dev/null +++ b/Source/VCExpr/VCExprAST.cs @@ -0,0 +1,1424 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// Prover-independent syntax trees for representing verification conditions +// The language can be seen as a simple polymorphically typed first-order logic, +// very similar to the expression language of Boogie + +namespace Microsoft.Boogie +{ + using Microsoft.Boogie.VCExprAST; + + public class VCExpressionGenerator + { + public static readonly VCExpr! False = new VCExprLiteral (Type.Bool); + public static readonly VCExpr! True = new VCExprLiteral (Type.Bool); + + private Function ControlFlowFunction = null; + public VCExpr! ControlFlowFunctionApplication(VCExpr! e1, VCExpr! e2) + { + if (ControlFlowFunction == null) { + Formal! first = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), true); + Formal! second = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), true); + VariableSeq! inputs = new VariableSeq(); + inputs.Add(first); + inputs.Add(second); + Formal! returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), false); + ControlFlowFunction = new Function(Token.NoToken, "ControlFlow", inputs, returnVar); + } + List args = new List(); + args.Add(e1); + args.Add(e2); + return Function(BoogieFunctionOp(ControlFlowFunction), args); + } + + public VCExpr! Integer(BigNum x) { + return new VCExprIntLit(x); + } + + public VCExpr! Function(VCExprOp! op, + List! arguments, + List! typeArguments) { + if (typeArguments.Count > 0) + return new VCExprMultiAry(op, arguments, typeArguments); + + switch (arguments.Count) { + case 0: return new VCExprNullary(op); + case 1: return new VCExprUnary(op, arguments); + case 2: return new VCExprBinary(op, arguments); + default: return new VCExprMultiAry(op, arguments); + } + } + + public VCExpr! Function(VCExprOp! op, List! arguments) { + return Function(op, arguments, VCExprNAry.EMPTY_TYPE_LIST); + } + + public VCExpr! Function(VCExprOp! op, params VCExpr[]! arguments) + requires forall{int i in (0:arguments.Length); arguments[i] != null}; + { + return Function(op, + HelperFuns.ToNonNullList(arguments), + VCExprNAry.EMPTY_TYPE_LIST); + } + + public VCExpr! Function(VCExprOp! op, VCExpr[]! arguments, Type[]! typeArguments) + requires forall{int i in (0:arguments.Length); arguments[i] != null}; + requires forall{int i in (0:typeArguments.Length); typeArguments[i] != null}; + { + return Function(op, + HelperFuns.ToNonNullList(arguments), + HelperFuns.ToNonNullList(typeArguments)); + } + + public VCExpr! Function(Function! op, List! arguments) { + return Function(BoogieFunctionOp(op), arguments, VCExprNAry.EMPTY_TYPE_LIST); + } + + public VCExpr! Function(Function! op, params VCExpr[]! arguments) + requires forall{int i in (0:arguments.Length); arguments[i] != null}; + { + return Function(BoogieFunctionOp(op), arguments); + } + + + // The following method should really be called "ReduceLeft". It must + // only be used for the binary operators "and" and "or" + public VCExpr! NAry(VCExprOp! op, List! args) { + return NAry(op, args.ToArray()); + } + + public VCExpr! NAry(VCExprOp! op, params VCExpr[]! args) + requires forall{int i in (0:args.Length); args[i] != null}; + requires op == AndOp || op == OrOp; { + bool and = (op == AndOp); + + VCExpr! e = and ? True : False; + foreach (VCExpr a in args) { + e = and ? AndSimp(e, (!)a) : OrSimp(e, (!)a); + } + return e; + } + + //////////////////////////////////////////////////////////////////////////////// + + public static readonly VCExprOp! NotOp = new VCExprNAryOp (1, Type.Bool); + public static readonly VCExprOp! EqOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! NeqOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! AndOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! OrOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! ImpliesOp = new VCExprNAryOp (2, Type.Bool); + + public VCExprDistinctOp! DistinctOp(int arity) { + return new VCExprDistinctOp (arity); + } + + public VCExpr! Not(List! args) + requires args.Count == 1; { + return Function(NotOp, args); + } + + public VCExpr! Not(VCExpr! e0) { + return Function(NotOp, e0); + } + public VCExpr! Eq(VCExpr! e0, VCExpr! e1) { + return Function(EqOp, e0, e1); + } + public VCExpr! Neq(VCExpr! e0, VCExpr! e1) { + return Function(NeqOp, e0, e1); + } + public VCExpr! And(VCExpr! e0, VCExpr! e1) { + return Function(AndOp, e0, e1); + } + public VCExpr! Or(VCExpr! e0, VCExpr! e1) { + return Function(OrOp, e0, e1); + } + public VCExpr! Implies(VCExpr! e0, VCExpr! e1) { + return Function(ImpliesOp, e0, e1); + } + public VCExpr! Distinct(List! args) { + if (args.Count <= 1) + // trivial case + return True; + return Function(DistinctOp(args.Count), args); + } + + /////////////////////////////////////////////////////////////////////////// + // Versions of the propositional operators that automatically simplify in + // certain cases (for example, if one of the operators is True or False) + + public VCExpr! NotSimp(VCExpr! e0) { + if (e0.Equals(True)) + return False; + if (e0.Equals(False)) + return True; + return Not(e0); + } + public VCExpr! AndSimp(VCExpr! e0, VCExpr! e1) { + if (e0.Equals(True)) + return e1; + if (e1.Equals(True)) + return e0; + if (e0.Equals(False) || e1.Equals(False)) + return False; + return And(e0, e1); + } + public VCExpr! OrSimp(VCExpr! e0, VCExpr! e1) { + if (e0.Equals(False)) + return e1; + if (e1.Equals(False)) + return e0; + if (e0.Equals(True) || e1.Equals(True)) + return True; + return Or(e0, e1); + } + public VCExpr! ImpliesSimp(VCExpr! e0, VCExpr! e1) { + if (e0.Equals(True)) + return e1; + if (e1.Equals(False)) + return NotSimp(e0); + if (e0.Equals(False) || e1.Equals(True)) + return True; + // attempt to save on the depth of expressions (to reduce chances of stack overflows) + while (e1 is VCExprBinary) { + VCExprBinary n = (VCExprBinary)e1; + if (n.Op == ImpliesOp) { + if (AndSize(n[0]) <= AndSize(e0)) { + // combine the antecedents + e0 = And(e0, n[0]); + e1 = n[1]; + continue; + } + } + break; + } + return Implies(e0, e1); + } + + /// + /// Returns some measure of the number of conjuncts in e. This could be the total number of conjuncts in all + /// top-most layers of the expression, or it can simply be the length of the left-prong of this and-tree. The + /// important thing is that: AndSize(e0) >= AndSize(31) ==> AndSize(And(e0,e1)) > AndSize(e0). + /// + int AndSize(VCExpr! e) { + int n = 1; + while (true) { + VCExprNAry nary = e as VCExprNAry; + if (nary != null && nary.Op == AndOp && 2 <= nary.Arity) { + e = nary[0]; + n++; + } else { + return n; + } + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Further operators + + public static readonly VCExprOp! AddOp = new VCExprNAryOp (2, Type.Int); + public static readonly VCExprOp! SubOp = new VCExprNAryOp (2, Type.Int); + public static readonly VCExprOp! MulOp = new VCExprNAryOp (2, Type.Int); + public static readonly VCExprOp! DivOp = new VCExprNAryOp (2, Type.Int); + public static readonly VCExprOp! ModOp = new VCExprNAryOp (2, Type.Int); + public static readonly VCExprOp! LtOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! LeOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! GtOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! GeOp = new VCExprNAryOp (2, Type.Bool); + public static readonly VCExprOp! SubtypeOp = new VCExprNAryOp (2, Type.Bool); + // ternary version of the subtype operator, the first argument of which gives + // the type of the compared terms + public static readonly VCExprOp! Subtype3Op = new VCExprNAryOp (3, Type.Bool); + public static readonly VCExprOp! IfThenElseOp = new VCExprIfThenElseOp(); + + public static readonly VCExprOp! TickleBoolOp = new VCExprCustomOp("tickleBool", 1, Type.Bool); + + public VCExprOp! BoogieFunctionOp(Function! func) { + return new VCExprBoogieFunctionOp(func); + } + + // Bitvector nodes + + public VCExpr! Bitvector(BvConst! bv) { + return Function(new VCExprBvOp(bv.Bits), Integer(bv.Value)); + } + + public VCExpr! BvExtract(VCExpr! bv, int bits, int start, int end) { + return Function(new VCExprBvExtractOp(start, end, bits), bv); + } + + public VCExpr! BvConcat(VCExpr! bv1, VCExpr! bv2) { + return Function(new VCExprBvConcatOp(bv1.Type.BvBits, bv2.Type.BvBits), bv1, bv2); + } + + public VCExpr! AtMost(VCExpr! smaller, VCExpr! greater) { + return Function(SubtypeOp, smaller, greater); + } + + + //////////////////////////////////////////////////////////////////////////////// + // Dispatcher for the visitor + + // the declared singleton operators + internal enum SingletonOp { NotOp, EqOp, NeqOp, AndOp, OrOp, ImpliesOp, + AddOp, SubOp, MulOp, + DivOp, ModOp, LtOp, LeOp, GtOp, GeOp, SubtypeOp, + Subtype3Op, BvConcatOp }; + internal static Dictionary! SingletonOpDict; + + static VCExpressionGenerator() { + SingletonOpDict = new Dictionary (); + SingletonOpDict.Add(NotOp, SingletonOp.NotOp); + SingletonOpDict.Add(EqOp, SingletonOp.EqOp); + SingletonOpDict.Add(NeqOp, SingletonOp.NeqOp); + SingletonOpDict.Add(AndOp, SingletonOp.AndOp); + SingletonOpDict.Add(OrOp, SingletonOp.OrOp); + SingletonOpDict.Add(ImpliesOp, SingletonOp.ImpliesOp); + SingletonOpDict.Add(AddOp, SingletonOp.AddOp); + SingletonOpDict.Add(SubOp, SingletonOp.SubOp); + SingletonOpDict.Add(MulOp, SingletonOp.MulOp); + SingletonOpDict.Add(DivOp, SingletonOp.DivOp); + SingletonOpDict.Add(ModOp, SingletonOp.ModOp); + SingletonOpDict.Add(LtOp, SingletonOp.LtOp); + SingletonOpDict.Add(LeOp, SingletonOp.LeOp); + SingletonOpDict.Add(GtOp, SingletonOp.GtOp); + SingletonOpDict.Add(GeOp, SingletonOp.GeOp); + SingletonOpDict.Add(SubtypeOp, SingletonOp.SubtypeOp); + SingletonOpDict.Add(Subtype3Op,SingletonOp.Subtype3Op); + } + + //////////////////////////////////////////////////////////////////////////////// + + + // Let-bindings + + public VCExprLetBinding! LetBinding(VCExprVar! v, VCExpr! e) { + return new VCExprLetBinding(v, e); + } + + // A "real" let expression. All let-bindings happen simultaneously, i.e., + // at this level the order of the bindings does not matter. It is possible to + // create expressions like "let x = y, y = 5 in ...". All bound variables are + // bound in all bound terms/formulas and can occur there, but the dependencies + // have to be acyclic + public VCExpr! Let(List! bindings, VCExpr! body) { + if (bindings.Count == 0) + // no empty let-bindings + return body; + return new VCExprLet(bindings, body); + } + + public VCExpr! Let(VCExpr! body, params VCExprLetBinding[]! bindings) + requires forall{int i in (0:bindings.Length); bindings[i] != null}; + { + return Let(HelperFuns.ToNonNullList(bindings), body); + } + + + /// + /// In contrast to the previous method, the following methods are not a general LET. + /// Instead, it + /// is a boolean "LET b = P in Q", where P and Q are predicates, that is allowed to be + /// encoded as "(b == P) ==> Q" or even as "(P ==> b) ==> Q" + /// (or "(P ==> b) and Q" in negative positions). + /// The method assumes that the variables in the bindings are unique in the entire formula + /// to be produced, which allows the implementation to ignore scope issues in the event that + /// it needs to generate an alternate expression for LET. + /// + + + // Turn let-bindings let v = E in ... into implications E ==> v + public VCExpr! AsImplications(List! bindings) { + VCExpr! antecedents = True; + foreach (VCExprLetBinding b in bindings) + // turn "LET_binding v = E" into "v <== E" + antecedents = AndSimp(antecedents, Implies(b.E, b.V)); + return antecedents; + } + + // Turn let-bindings let v = E in ... into equations v == E + public VCExpr! AsEquations(List! bindings) { + VCExpr! antecedents = True; + foreach (VCExprLetBinding b in bindings) + // turn "LET_binding v = E" into "v <== E" + antecedents = AndSimp(antecedents, Eq(b.E, b.V)); + return antecedents; + } + + + + // Maps + + public VCExpr! Select(params VCExpr[]! allArgs) + requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; + { + return Function(new VCExprSelectOp(allArgs.Length - 1, 0), + HelperFuns.ToNonNullList(allArgs), + VCExprNAry.EMPTY_TYPE_LIST); + } + + public VCExpr! Select(VCExpr[]! allArgs, Type[]! typeArgs) + requires 1 <= allArgs.Length; + requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; + requires forall{int i in (0:typeArgs.Length); typeArgs[i] != null}; + { + return Function(new VCExprSelectOp(allArgs.Length - 1, typeArgs.Length), + allArgs, typeArgs); + } + + public VCExpr! Select(List! allArgs, List! typeArgs) + requires 1 <= allArgs.Count; + { + return Function(new VCExprSelectOp(allArgs.Count - 1, typeArgs.Count), + allArgs, typeArgs); + } + + public VCExpr! Store(params VCExpr[]! allArgs) + requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; + { + return Function(new VCExprStoreOp(allArgs.Length - 2, 0), + HelperFuns.ToNonNullList(allArgs), + VCExprNAry.EMPTY_TYPE_LIST); + } + + public VCExpr! Store(VCExpr[]! allArgs, Type[]! typeArgs) + requires 2 <= allArgs.Length; + requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; + requires forall{int i in (0:typeArgs.Length); typeArgs[i] != null}; + { + return Function(new VCExprStoreOp(allArgs.Length - 2, typeArgs.Length), + allArgs, typeArgs); + } + + public VCExpr! Store(List! allArgs, List! typeArgs) + requires 2 <= allArgs.Count; + { + return Function(new VCExprStoreOp(allArgs.Count - 2, typeArgs.Count), + allArgs, typeArgs); + } + + + // Labels + + public VCExprLabelOp! LabelOp(bool pos, string! l) { + return new VCExprLabelOp(pos, l); + } + + public VCExpr! LabelNeg(string! label, VCExpr! e) { + if (e.Equals(True)) { + return e; // don't bother putting negative labels around True (which will expose the True to further peephole optimizations) + } + return Function(LabelOp(false, label), e); + } + public VCExpr! LabelPos(string! label, VCExpr! e) { + return Function(LabelOp(true, label), e); + } + + // Quantifiers + + public VCExpr! Quantify(Quantifier quan, + List! typeParams, List! vars, + List! triggers, VCQuantifierInfos! infos, + VCExpr! body) { + return new VCExprQuantifier(quan, typeParams, vars, triggers, infos, body); + } + + public VCExpr! Forall(List! typeParams, List! vars, + List! triggers, VCQuantifierInfos! infos, + VCExpr! body) { + return Quantify(Quantifier.ALL, typeParams, vars, triggers, infos, body); + } + public VCExpr! Forall(List! vars, + List! triggers, + string! qid, VCExpr! body) { + return Quantify(Quantifier.ALL, new List (), vars, + triggers, new VCQuantifierInfos (qid, -1, false, null), body); + } + public VCExpr! Forall(List! vars, + List! triggers, + VCExpr! body) { + return Quantify(Quantifier.ALL, new List (), vars, + triggers, new VCQuantifierInfos (null, -1, false, null), body); + } + public VCExpr! Forall(VCExprVar! var, VCTrigger! trigger, VCExpr! body) { + return Forall(HelperFuns.ToNonNullList(var), HelperFuns.ToNonNullList(trigger), body); + } + public VCExpr! Exists(List! typeParams, List! vars, + List! triggers, VCQuantifierInfos! infos, + VCExpr! body) { + return Quantify(Quantifier.EX, typeParams, vars, triggers, infos, body); + } + public VCExpr! Exists(List! vars, + List! triggers, + VCExpr! body) { + return Quantify(Quantifier.EX, new List (), vars, + triggers, new VCQuantifierInfos (null, -1, false, null), body); + } + public VCExpr! Exists(VCExprVar! var, VCTrigger! trigger, VCExpr! body) { + return Exists(HelperFuns.ToNonNullList(var), HelperFuns.ToNonNullList(trigger), body); + } + + public VCTrigger! Trigger(bool pos, List! exprs) { + return new VCTrigger(pos, exprs); + } + + public VCTrigger! Trigger(bool pos, params VCExpr[]! exprs) + requires forall{int i in (0:exprs.Length); exprs[i] != null}; + { + return Trigger(pos, HelperFuns.ToNonNullList(exprs)); + } + + // Reference to a bound or free variable + + public VCExprVar! Variable(string! name, Type! type) { + return new VCExprVar(name, type); + } + } +} + +namespace Microsoft.Boogie.VCExprAST +{ + + public class HelperFuns { + public static bool SameElements(IEnumerable! a, IEnumerable! b) { + IEnumerator ia = a.GetEnumerator(); + IEnumerator ib = b.GetEnumerator(); + while (true) { + if (ia.MoveNext()) { + if (ib.MoveNext()) { + if (!((!)ia.Current).Equals(ib.Current)) + return false; + } else { + return false; + } + } else { + return !ib.MoveNext(); + } + } + return true; + } + + public static int PolyHash(int init, int factor, IEnumerable! a) { + int res = init; + foreach(object x in a) + res = res * factor + ((!)x).GetHashCode(); + return res; + } + + public static List! ToList(IEnumerable! l) { + List! res = new List (); + foreach (T x in l) + res.Add(x); + return res; + } + + public static TypeSeq! ToTypeSeq(VCExpr[]! exprs, int startIndex) + requires forall{int i in (0:exprs.Length); exprs[i] != null}; + { + TypeSeq! res = new TypeSeq (); + for (int i = startIndex; i < exprs.Length; ++i) + res.Add(((!)exprs[i]).Type); + return res; + } + + public static List! ToNonNullList (params T[]! args) { + List! res = new List (args.Length); + foreach (T t in args) + res.Add((!)t); + return res; + } + + public static IDictionary! Clone(IDictionary! dict) { + IDictionary! res = new Dictionary (dict.Count); + foreach (KeyValuePair pair in dict) + res.Add(pair); + return res; + } + } + + public abstract class VCExpr { + public abstract Type! Type { get; } + + public abstract Result Accept(IVCExprVisitor! visitor, Arg arg); + + [Pure] + public override string! ToString() { + StringWriter! sw = new StringWriter(); + VCExprPrinter! printer = new VCExprPrinter (); + printer.Print(this, sw); + return (!)sw.ToString(); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // Literal expressions + + public class VCExprLiteral : VCExpr { + private readonly Type! LitType; + public override Type! Type { get { return LitType; } } + internal VCExprLiteral(Type! type) { + this.LitType = type; + } + public override Result Accept(IVCExprVisitor! visitor, Arg arg) { + return visitor.Visit(this, arg); + } + } + + public class VCExprIntLit : VCExprLiteral + { + public readonly BigNum Val; + internal VCExprIntLit(BigNum val) { + base(Type.Int); + this.Val = val; + } + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprIntLit) + return Val == ((VCExprIntLit)that).Val; + return false; + } + [Pure] + public override int GetHashCode() { + return Val.GetHashCode() * 72321; + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // Operator expressions with fixed arity + + public abstract class VCExprNAry : VCExpr, IEnumerable { + public readonly VCExprOp! Op; + public int Arity { get { return Op.Arity; } } + public int TypeParamArity { get { return Op.TypeParamArity; } } + public int Length { get { return Arity; } } + // the sub-expressions of the expression + public abstract VCExpr! this[int index] { get; } + + // the type arguments + public abstract List! TypeArguments { get; } + + [Pure] [GlobalAccess(false)] [Escapes(true,false)] + public IEnumerator! GetEnumerator() { + for (int i = 0; i < Arity; ++i) + yield return this[i]; + } + [Pure] [GlobalAccess(false)] [Escapes(true,false)] + IEnumerator! System.Collections.IEnumerable.GetEnumerator() { + for (int i = 0; i < Arity; ++i) + yield return this[i]; + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprNAry) { + // we compare the subterms iteratively (not recursively) + // to avoid stack overflows + + VCExprNAryEnumerator enum0 = new VCExprNAryEnumerator(this); + VCExprNAryEnumerator enum1 = new VCExprNAryEnumerator((VCExprNAry)that); + + while (true) { + bool next0 = enum0.MoveNext(); + bool next1 = enum1.MoveNext(); + if (next0 != next1) + return false; + if (!next0) + return true; + + VCExprNAry nextExprNAry0 = enum0.Current as VCExprNAry; + VCExprNAry nextExprNAry1 = enum1.Current as VCExprNAry; + + if ((nextExprNAry0 == null) != (nextExprNAry1 == null)) + return false; + if (nextExprNAry0 != null && nextExprNAry1 != null) { + if (!nextExprNAry0.Op.Equals(nextExprNAry1.Op)) + return false; + } else { + if (!((!)enum0.Current).Equals(enum1.Current)) + return false; + } + } + } + return false; + } + [Pure] + public override int GetHashCode() { + return HelperFuns.PolyHash(Op.GetHashCode() * 123 + Arity * 61521, + 3, this); + } + + internal VCExprNAry(VCExprOp! op) { + this.Op = op; + } + public override Result Accept(IVCExprVisitor! visitor, Arg arg) { + return visitor.Visit(this, arg); + } + public Result Accept(IVCExprOpVisitor! visitor, Arg arg) { + return Op.Accept(this, visitor, arg); + } + + internal static readonly List! EMPTY_TYPE_LIST = new List (); + internal static readonly List! EMPTY_VCEXPR_LIST = new List (); + } + + // We give specialised implementations for nullary, unary and binary expressions + + internal class VCExprNullary : VCExprNAry { + private readonly Type! ExprType; + public override Type! Type { get { return ExprType; } } + public override VCExpr! this[int index] { get { + assert false; // no arguments + } } + + // the type arguments + public override List! TypeArguments { get { + return EMPTY_TYPE_LIST; + } } + + internal VCExprNullary(VCExprOp! op) + requires op.Arity == 0 && op.TypeParamArity == 0; { + base(op); + this.ExprType = op.InferType(EMPTY_VCEXPR_LIST, EMPTY_TYPE_LIST); + } + } + + internal class VCExprUnary : VCExprNAry { + private readonly VCExpr! Argument; + private readonly Type! ExprType; + public override Type! Type { get { return ExprType; } } + public override VCExpr! this[int index] { get { + assume index == 0; + return Argument; + } } + + // the type arguments + public override List! TypeArguments { get { + return EMPTY_TYPE_LIST; + } } + + internal VCExprUnary(VCExprOp! op, List! arguments) + requires op.Arity == 1 && op.TypeParamArity == 0 && arguments.Count == 1; { + base(op); + this.Argument = arguments[0]; + this.ExprType = + op.InferType(arguments, EMPTY_TYPE_LIST); + } + + internal VCExprUnary(VCExprOp! op, VCExpr! argument) + requires op.Arity == 1 && op.TypeParamArity == 0; { + base(op); + this.Argument = argument; + // PR: could be optimised so that the argument does + // not have to be boxed in an array each time + this.ExprType = + op.InferType(HelperFuns.ToNonNullList(argument), EMPTY_TYPE_LIST); + } + } + + internal class VCExprBinary : VCExprNAry { + private readonly VCExpr! Argument0; + private readonly VCExpr! Argument1; + private readonly Type! ExprType; + public override Type! Type { get { return ExprType; } } + public override VCExpr! this[int index] { get { + switch (index) { + case 0: return Argument0; + case 1: return Argument1; + default: assert false; + } + } } + + // the type arguments + public override List! TypeArguments { get { + return EMPTY_TYPE_LIST; + } } + + internal VCExprBinary(VCExprOp! op, List! arguments) + requires op.Arity == 2 && op.TypeParamArity == 0 && arguments.Count == 2; { + base(op); + this.Argument0 = arguments[0]; + this.Argument1 = arguments[1]; + this.ExprType = op.InferType(arguments, EMPTY_TYPE_LIST); + } + + internal VCExprBinary(VCExprOp! op, VCExpr! argument0, VCExpr! argument1) + requires op.Arity == 2 && op.TypeParamArity == 0; { + base(op); + this.Argument0 = argument0; + this.Argument1 = argument1; + // PR: could be optimised so that the arguments do + // not have to be boxed in an array each time + this.ExprType = + op.InferType(HelperFuns.ToNonNullList(argument0, argument1), + EMPTY_TYPE_LIST); + } + } + + internal class VCExprMultiAry : VCExprNAry { + private readonly List! Arguments; + private readonly List! TypeArgumentsAttr; + + private readonly Type! ExprType; + public override Type! Type { get { return ExprType; } } + public override VCExpr! this[int index] { get { + assume index >= 0 && index < Arity; + return (!)Arguments[index]; + } } + + // the type arguments + public override List! TypeArguments { get { + return TypeArgumentsAttr; + } } + + internal VCExprMultiAry(VCExprOp! op, List! arguments) { + this(op, arguments, EMPTY_TYPE_LIST); + } + internal VCExprMultiAry(VCExprOp! op, List! arguments, List! typeArguments) + requires (arguments.Count > 2 || typeArguments.Count > 0); + requires op.Arity == arguments.Count; + requires op.TypeParamArity == typeArguments.Count; + { + base(op); + this.Arguments = arguments; + this.TypeArgumentsAttr = typeArguments; + this.ExprType = op.InferType(arguments, typeArguments); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // The various operators available + + public abstract class VCExprOp { + // the number of value parameters + public abstract int Arity { get; } + // the number of type parameters + public abstract int TypeParamArity { get; } + + public abstract Type! InferType(List! args, List! typeArgs); + + public virtual Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + VCExpressionGenerator.SingletonOp op; + if (VCExpressionGenerator.SingletonOpDict.TryGetValue(this, out op)) { + switch(op) { + case VCExpressionGenerator.SingletonOp.NotOp: + return visitor.VisitNotOp(expr, arg); + case VCExpressionGenerator.SingletonOp.EqOp: + return visitor.VisitEqOp(expr, arg); + case VCExpressionGenerator.SingletonOp.NeqOp: + return visitor.VisitNeqOp(expr, arg); + case VCExpressionGenerator.SingletonOp.AndOp: + return visitor.VisitAndOp(expr, arg); + case VCExpressionGenerator.SingletonOp.OrOp: + return visitor.VisitOrOp(expr, arg); + case VCExpressionGenerator.SingletonOp.ImpliesOp: + return visitor.VisitImpliesOp(expr, arg); + case VCExpressionGenerator.SingletonOp.AddOp: + return visitor.VisitAddOp(expr, arg); + case VCExpressionGenerator.SingletonOp.SubOp: + return visitor.VisitSubOp(expr, arg); + case VCExpressionGenerator.SingletonOp.MulOp: + return visitor.VisitMulOp(expr, arg); + case VCExpressionGenerator.SingletonOp.DivOp: + return visitor.VisitDivOp(expr, arg); + case VCExpressionGenerator.SingletonOp.ModOp: + return visitor.VisitModOp(expr, arg); + case VCExpressionGenerator.SingletonOp.LtOp: + return visitor.VisitLtOp(expr, arg); + case VCExpressionGenerator.SingletonOp.LeOp: + return visitor.VisitLeOp(expr, arg); + case VCExpressionGenerator.SingletonOp.GtOp: + return visitor.VisitGtOp(expr, arg); + case VCExpressionGenerator.SingletonOp.GeOp: + return visitor.VisitGeOp(expr, arg); + case VCExpressionGenerator.SingletonOp.SubtypeOp: + return visitor.VisitSubtypeOp(expr, arg); + case VCExpressionGenerator.SingletonOp.Subtype3Op: + return visitor.VisitSubtype3Op(expr, arg); + case VCExpressionGenerator.SingletonOp.BvConcatOp: + return visitor.VisitBvConcatOp(expr, arg); + default: + assert false; + } + } else { + assert false; + } + } + } + + public class VCExprNAryOp : VCExprOp { + private readonly Type! OpType; + private readonly int OpArity; + + public override int Arity { get { return OpArity; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return OpType; + } + + internal VCExprNAryOp(int arity, Type! type) { + this.OpArity = arity; + this.OpType = type; + } + } + + public class VCExprDistinctOp : VCExprNAryOp { + internal VCExprDistinctOp(int arity) { + base(arity, Type.Bool); + } + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprDistinctOp) + return Arity == ((VCExprDistinctOp)that).Arity; + return false; + } + [Pure] + public override int GetHashCode() { + return Arity * 917632481; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitDistinctOp(expr, arg); + } + } + + public class VCExprLabelOp : VCExprOp { + public override int Arity { get { return 1; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return args[0].Type; + } + + public readonly bool pos; + public readonly string! label; + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprLabelOp) { + VCExprLabelOp! thatOp = (VCExprLabelOp)that; + return this.pos == thatOp.pos && this.label.Equals(thatOp.label); + } + return false; + } + [Pure] + public override int GetHashCode() { + return (pos ? 9817231 : 7198639) + label.GetHashCode(); + } + + internal VCExprLabelOp(bool pos, string! l) { + this.pos = pos; + this.label = pos ? "+" + l : "@" + l; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitLabelOp(expr, arg); + } + } + + public class VCExprSelectOp : VCExprOp { + private readonly int MapArity; + private readonly int MapTypeParamArity; + public override int Arity { get { return MapArity + 1; } } + public override int TypeParamArity { get { return MapTypeParamArity; } } + + public override Type! InferType(List! args, List! typeArgs) { + MapType! mapType = args[0].Type.AsMap; + assert TypeParamArity == mapType.TypeParameters.Length; + IDictionary! subst = new Dictionary (); + for (int i = 0; i < TypeParamArity; ++i) + subst.Add(mapType.TypeParameters[i], typeArgs[i]); + return mapType.Result.Substitute(subst); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprSelectOp) + return Arity == ((VCExprSelectOp)that).Arity && + TypeParamArity == ((VCExprSelectOp)that).TypeParamArity; + return false; + } + [Pure] + public override int GetHashCode() { + return Arity * 1212481 + TypeParamArity * 298741; + } + + internal VCExprSelectOp(int arity, int typeParamArity) + requires 0 <= arity && 0 <= typeParamArity; + { + this.MapArity = arity; + this.MapTypeParamArity = typeParamArity; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitSelectOp(expr, arg); + } + } + + public class VCExprStoreOp : VCExprOp { + private readonly int MapArity; + private readonly int MapTypeParamArity; + public override int Arity { get { return MapArity + 2; } } + // stores never need explicit type parameters, because also the + // rhs is a value argument + public override int TypeParamArity { get { return MapTypeParamArity; } } + + public override Type! InferType(List! args, List! typeArgs) { + return args[0].Type; + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprStoreOp) + return Arity == ((VCExprStoreOp)that).Arity; + return false; + } + [Pure] + public override int GetHashCode() { + return Arity * 91361821; + } + + internal VCExprStoreOp(int arity, int typeParamArity) + requires 0 <= arity && 0 <= typeParamArity; + { + this.MapArity = arity; + this.MapTypeParamArity = typeParamArity; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitStoreOp(expr, arg); + } + } + + public class VCExprIfThenElseOp : VCExprOp { + public override int Arity { get { return 3; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return args[1].Type; + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprIfThenElseOp) + return true; + return false; + } + [Pure] + public override int GetHashCode() { + return 1; + } + + internal VCExprIfThenElseOp() { + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitIfThenElseOp(expr, arg); + } + } + + public class VCExprCustomOp : VCExprOp { + public readonly string! Name; + int arity; + public readonly Type! Type; + public VCExprCustomOp(string! name, int arity, Type! type) { + this.Name = name; + this.arity = arity; + this.Type = type; + } + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + VCExprCustomOp t = that as VCExprCustomOp; + if (t == null) + return false; + return this.Name == t.Name && this.arity == t.arity && this.Type == t.Type; + } + public override int Arity { get { return arity; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { return Type; } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitCustomOp(expr, arg); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // Bitvector operators + + public class VCExprBvOp : VCExprOp { + public readonly int Bits; + + public override int Arity { get { return 1; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return Type.GetBvType(Bits); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprBvOp) + return this.Bits == ((VCExprBvOp)that).Bits; + return false; + } + [Pure] + public override int GetHashCode() { + return Bits * 81748912; + } + + internal VCExprBvOp(int bits) { + this.Bits = bits; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitBvOp(expr, arg); + } + } + + public class VCExprBvExtractOp : VCExprOp { + public readonly int Start; + public readonly int End; + public readonly int Total; // the number of bits from which the End-Start bits are extracted + + public override int Arity { get { return 1; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return Type.GetBvType(End - Start); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprBvExtractOp) { + VCExprBvExtractOp! thatExtract = (VCExprBvExtractOp)that; + return this.Start == thatExtract.Start && this.End == thatExtract.End && this.Total == thatExtract.Total; + } + return false; + } + [Pure] + public override int GetHashCode() { + return Start * 81912 + End * 978132 + Total * 571289; + } + + internal VCExprBvExtractOp(int start, int end, int total) + requires 0 <= start && start <= end && end <= total; + { + this.Start = start; + this.End = end; + this.Total = total; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitBvExtractOp(expr, arg); + } + } + + public class VCExprBvConcatOp : VCExprOp { + public readonly int LeftSize; + public readonly int RightSize; + + public override int Arity { get { return 2; } } + public override int TypeParamArity { get { return 0; } } + public override Type! InferType(List! args, List! typeArgs) { + return Type.GetBvType(args[0].Type.BvBits + args[1].Type.BvBits); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprBvConcatOp) { + VCExprBvConcatOp thatConcat = (VCExprBvConcatOp)that; + return this.LeftSize == thatConcat.LeftSize && this.RightSize == thatConcat.RightSize; + } + return false; + } + [Pure] + public override int GetHashCode() { + return LeftSize * 81912 + RightSize * 978132; + } + + internal VCExprBvConcatOp(int leftSize, int rightSize) + requires 0 <= leftSize && 0 <= rightSize; + { + this.LeftSize = leftSize; + this.RightSize = rightSize; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitBvConcatOp(expr, arg); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // References to user-defined Boogie functions + + public class VCExprBoogieFunctionOp : VCExprOp { + public readonly Function! Func; + + public override int Arity { get { return Func.InParams.Length; } } + public override int TypeParamArity { get { return Func.TypeParameters.Length; } } + public override Type! InferType(List! args, List! typeArgs) { + assert TypeParamArity == Func.TypeParameters.Length; + if (TypeParamArity == 0) + return ((!)Func.OutParams[0]).TypedIdent.Type; + IDictionary! subst = new Dictionary (TypeParamArity); + for (int i = 0; i < TypeParamArity; ++i) + subst.Add(Func.TypeParameters[i], typeArgs[i]); + return ((!)Func.OutParams[0]).TypedIdent.Type.Substitute(subst); + } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprBoogieFunctionOp) + return this.Func.Equals(((VCExprBoogieFunctionOp)that).Func); + return false; + } + [Pure] + public override int GetHashCode() { + return Func.GetHashCode() + 18731; + } + + // we require that the result type of the expression is specified, because we + // do not want to perform full type inference at this point + internal VCExprBoogieFunctionOp(Function! func) { + this.Func = func; + } + public override Result Accept + (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { + return visitor.VisitBoogieFunctionOp(expr, arg); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // Binders (quantifiers and let-expressions). We introduce our own class for + // term variables, but use the Boogie-AST class for type variables + + public class VCExprVar : VCExpr { + // the name of the variable. Note that the name is not used for comparison, + // i.e., there can be two distinct variables with the same name + public readonly string! Name; + private readonly Type! VarType; + public override Type! Type { get { return VarType; } } + + internal VCExprVar(string! name, Type! type) { + this.Name = name; + this.VarType = type; + } + public override Result Accept(IVCExprVisitor! visitor, Arg arg) { + return visitor.Visit(this, arg); + } + } + + public abstract class VCExprBinder : VCExpr { + public readonly VCExpr! Body; + public readonly List! TypeParameters; + public readonly List! BoundVars; + + public override Type! Type { get { return Body.Type; } } + + internal VCExprBinder(List! typeParams, + List! boundVars, + VCExpr! body) + requires boundVars.Count + typeParams.Count > 0; { // only nontrivial binders ... + this.TypeParameters = typeParams; + this.BoundVars = boundVars; + this.Body = body; + } + } + + public class VCTrigger { + public readonly bool Pos; + public readonly List! Exprs; + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCTrigger) { + VCTrigger! thatTrigger = (VCTrigger)that; + return this.Pos == thatTrigger.Pos && + HelperFuns.SameElements(this.Exprs, thatTrigger.Exprs); + } + return false; + } + [Pure] + public override int GetHashCode() { + return (Pos ? 913821 : 871334) + + HelperFuns.PolyHash(123, 7, this.Exprs); + } + + public VCTrigger(bool pos, List! exprs) { + this.Pos = pos; + this.Exprs = exprs; + } + } + + public class VCQuantifierInfos { + public readonly string qid; + public readonly int uniqueId; + public readonly bool bvZ3Native; + public QKeyValue attributes; + + public VCQuantifierInfos(string qid, int uniqueId, bool bvZ3Native, QKeyValue attributes) { + this.qid = qid; + this.uniqueId = uniqueId; + this.bvZ3Native = bvZ3Native; + this.attributes = attributes; + } + } + + public enum Quantifier { ALL, EX }; + + public class VCExprQuantifier : VCExprBinder { + public readonly Quantifier Quan; + + public readonly List! Triggers; + public readonly VCQuantifierInfos! Infos; + + // Equality is /not/ modulo bound renaming at this point + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprQuantifier) { + VCExprQuantifier! thatQuan = (VCExprQuantifier)that; + return this.Quan == thatQuan.Quan && + HelperFuns.SameElements(this.Triggers, thatQuan.Triggers) && + HelperFuns.SameElements(this.TypeParameters, thatQuan.TypeParameters) && + HelperFuns.SameElements(this.BoundVars, thatQuan.BoundVars) && + this.Body.Equals(thatQuan.Body); + } + return false; + } + [Pure] + public override int GetHashCode() { + return Quan.GetHashCode() + + HelperFuns.PolyHash(973219, 7, TypeParameters) + + HelperFuns.PolyHash(998431, 9, BoundVars) + + HelperFuns.PolyHash(123, 11, Triggers); + } + + internal VCExprQuantifier(Quantifier kind, + List! typeParams, + List! boundVars, + List! triggers, + VCQuantifierInfos! infos, + VCExpr! body) { + base(typeParams, boundVars, body); + this.Quan = kind; + this.Triggers = triggers; + this.Infos = infos; + } + public override Result Accept(IVCExprVisitor! visitor, Arg arg) { + return visitor.Visit(this, arg); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // Let-Bindings + + public class VCExprLetBinding { + public readonly VCExprVar! V; + public readonly VCExpr! E; + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprLetBinding) { + VCExprLetBinding! thatB = (VCExprLetBinding)that; + return this.V.Equals(thatB.V) && this.E.Equals(thatB.E); + } + return false; + } + [Pure] + public override int GetHashCode() { + return V.GetHashCode() * 71261 + E.GetHashCode(); + } + + internal VCExprLetBinding(VCExprVar! v, VCExpr! e) { + this.V = v; + this.E = e; + assert v.Type.Equals(e.Type); + } + } + + public class VCExprLet : VCExprBinder, IEnumerable { + private readonly List! Bindings; + + public int Length { get { return Bindings.Count; } } + public VCExprLetBinding! this[int index] { get { + return Bindings[index]; + } } + + [Pure][Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (Object.ReferenceEquals(this, that)) + return true; + if (that is VCExprLet) { + VCExprLet! thatLet = (VCExprLet)that; + return this.Body.Equals(thatLet.Body) && + HelperFuns.SameElements(this, (VCExprLet)that); + } + return false; + } + [Pure] + public override int GetHashCode() { + return HelperFuns.PolyHash(Body.GetHashCode(), 9, Bindings); + } + + [Pure] [GlobalAccess(false)] [Escapes(true,false)] + public IEnumerator! GetEnumerator() { + return Bindings.GetEnumerator(); + } + [Pure] [GlobalAccess(false)] [Escapes(true,false)] + IEnumerator! System.Collections.IEnumerable.GetEnumerator() { + return Bindings.GetEnumerator(); + } + + private static List! toSeq(List! bindings) { + List! res = new List (); + foreach (VCExprLetBinding! b in bindings) + res.Add(b.V); + return res; + } + + internal VCExprLet(List! bindings, + VCExpr! body) { + base(new List (), toSeq(bindings), body); + this.Bindings = bindings; + } + public override Result Accept(IVCExprVisitor! visitor, Arg arg) { + return visitor.Visit(this, arg); + } + } +} diff --git a/Source/VCExpr/VCExprAST.ssc b/Source/VCExpr/VCExprAST.ssc deleted file mode 100644 index 7e5b31f1..00000000 --- a/Source/VCExpr/VCExprAST.ssc +++ /dev/null @@ -1,1424 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// Prover-independent syntax trees for representing verification conditions -// The language can be seen as a simple polymorphically typed first-order logic, -// very similar to the expression language of Boogie - -namespace Microsoft.Boogie -{ - using Microsoft.Boogie.VCExprAST; - - public class VCExpressionGenerator - { - public static readonly VCExpr! False = new VCExprLiteral (Type.Bool); - public static readonly VCExpr! True = new VCExprLiteral (Type.Bool); - - private Function ControlFlowFunction = null; - public VCExpr! ControlFlowFunctionApplication(VCExpr! e1, VCExpr! e2) - { - if (ControlFlowFunction == null) { - Formal! first = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), true); - Formal! second = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), true); - VariableSeq! inputs = new VariableSeq(); - inputs.Add(first); - inputs.Add(second); - Formal! returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Int), false); - ControlFlowFunction = new Function(Token.NoToken, "ControlFlow", inputs, returnVar); - } - List args = new List(); - args.Add(e1); - args.Add(e2); - return Function(BoogieFunctionOp(ControlFlowFunction), args); - } - - public VCExpr! Integer(BigNum x) { - return new VCExprIntLit(x); - } - - public VCExpr! Function(VCExprOp! op, - List! arguments, - List! typeArguments) { - if (typeArguments.Count > 0) - return new VCExprMultiAry(op, arguments, typeArguments); - - switch (arguments.Count) { - case 0: return new VCExprNullary(op); - case 1: return new VCExprUnary(op, arguments); - case 2: return new VCExprBinary(op, arguments); - default: return new VCExprMultiAry(op, arguments); - } - } - - public VCExpr! Function(VCExprOp! op, List! arguments) { - return Function(op, arguments, VCExprNAry.EMPTY_TYPE_LIST); - } - - public VCExpr! Function(VCExprOp! op, params VCExpr[]! arguments) - requires forall{int i in (0:arguments.Length); arguments[i] != null}; - { - return Function(op, - HelperFuns.ToNonNullList(arguments), - VCExprNAry.EMPTY_TYPE_LIST); - } - - public VCExpr! Function(VCExprOp! op, VCExpr[]! arguments, Type[]! typeArguments) - requires forall{int i in (0:arguments.Length); arguments[i] != null}; - requires forall{int i in (0:typeArguments.Length); typeArguments[i] != null}; - { - return Function(op, - HelperFuns.ToNonNullList(arguments), - HelperFuns.ToNonNullList(typeArguments)); - } - - public VCExpr! Function(Function! op, List! arguments) { - return Function(BoogieFunctionOp(op), arguments, VCExprNAry.EMPTY_TYPE_LIST); - } - - public VCExpr! Function(Function! op, params VCExpr[]! arguments) - requires forall{int i in (0:arguments.Length); arguments[i] != null}; - { - return Function(BoogieFunctionOp(op), arguments); - } - - - // The following method should really be called "ReduceLeft". It must - // only be used for the binary operators "and" and "or" - public VCExpr! NAry(VCExprOp! op, List! args) { - return NAry(op, args.ToArray()); - } - - public VCExpr! NAry(VCExprOp! op, params VCExpr[]! args) - requires forall{int i in (0:args.Length); args[i] != null}; - requires op == AndOp || op == OrOp; { - bool and = (op == AndOp); - - VCExpr! e = and ? True : False; - foreach (VCExpr a in args) { - e = and ? AndSimp(e, (!)a) : OrSimp(e, (!)a); - } - return e; - } - - //////////////////////////////////////////////////////////////////////////////// - - public static readonly VCExprOp! NotOp = new VCExprNAryOp (1, Type.Bool); - public static readonly VCExprOp! EqOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! NeqOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! AndOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! OrOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! ImpliesOp = new VCExprNAryOp (2, Type.Bool); - - public VCExprDistinctOp! DistinctOp(int arity) { - return new VCExprDistinctOp (arity); - } - - public VCExpr! Not(List! args) - requires args.Count == 1; { - return Function(NotOp, args); - } - - public VCExpr! Not(VCExpr! e0) { - return Function(NotOp, e0); - } - public VCExpr! Eq(VCExpr! e0, VCExpr! e1) { - return Function(EqOp, e0, e1); - } - public VCExpr! Neq(VCExpr! e0, VCExpr! e1) { - return Function(NeqOp, e0, e1); - } - public VCExpr! And(VCExpr! e0, VCExpr! e1) { - return Function(AndOp, e0, e1); - } - public VCExpr! Or(VCExpr! e0, VCExpr! e1) { - return Function(OrOp, e0, e1); - } - public VCExpr! Implies(VCExpr! e0, VCExpr! e1) { - return Function(ImpliesOp, e0, e1); - } - public VCExpr! Distinct(List! args) { - if (args.Count <= 1) - // trivial case - return True; - return Function(DistinctOp(args.Count), args); - } - - /////////////////////////////////////////////////////////////////////////// - // Versions of the propositional operators that automatically simplify in - // certain cases (for example, if one of the operators is True or False) - - public VCExpr! NotSimp(VCExpr! e0) { - if (e0.Equals(True)) - return False; - if (e0.Equals(False)) - return True; - return Not(e0); - } - public VCExpr! AndSimp(VCExpr! e0, VCExpr! e1) { - if (e0.Equals(True)) - return e1; - if (e1.Equals(True)) - return e0; - if (e0.Equals(False) || e1.Equals(False)) - return False; - return And(e0, e1); - } - public VCExpr! OrSimp(VCExpr! e0, VCExpr! e1) { - if (e0.Equals(False)) - return e1; - if (e1.Equals(False)) - return e0; - if (e0.Equals(True) || e1.Equals(True)) - return True; - return Or(e0, e1); - } - public VCExpr! ImpliesSimp(VCExpr! e0, VCExpr! e1) { - if (e0.Equals(True)) - return e1; - if (e1.Equals(False)) - return NotSimp(e0); - if (e0.Equals(False) || e1.Equals(True)) - return True; - // attempt to save on the depth of expressions (to reduce chances of stack overflows) - while (e1 is VCExprBinary) { - VCExprBinary n = (VCExprBinary)e1; - if (n.Op == ImpliesOp) { - if (AndSize(n[0]) <= AndSize(e0)) { - // combine the antecedents - e0 = And(e0, n[0]); - e1 = n[1]; - continue; - } - } - break; - } - return Implies(e0, e1); - } - - /// - /// Returns some measure of the number of conjuncts in e. This could be the total number of conjuncts in all - /// top-most layers of the expression, or it can simply be the length of the left-prong of this and-tree. The - /// important thing is that: AndSize(e0) >= AndSize(31) ==> AndSize(And(e0,e1)) > AndSize(e0). - /// - int AndSize(VCExpr! e) { - int n = 1; - while (true) { - VCExprNAry nary = e as VCExprNAry; - if (nary != null && nary.Op == AndOp && 2 <= nary.Arity) { - e = nary[0]; - n++; - } else { - return n; - } - } - } - - //////////////////////////////////////////////////////////////////////////////// - // Further operators - - public static readonly VCExprOp! AddOp = new VCExprNAryOp (2, Type.Int); - public static readonly VCExprOp! SubOp = new VCExprNAryOp (2, Type.Int); - public static readonly VCExprOp! MulOp = new VCExprNAryOp (2, Type.Int); - public static readonly VCExprOp! DivOp = new VCExprNAryOp (2, Type.Int); - public static readonly VCExprOp! ModOp = new VCExprNAryOp (2, Type.Int); - public static readonly VCExprOp! LtOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! LeOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! GtOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! GeOp = new VCExprNAryOp (2, Type.Bool); - public static readonly VCExprOp! SubtypeOp = new VCExprNAryOp (2, Type.Bool); - // ternary version of the subtype operator, the first argument of which gives - // the type of the compared terms - public static readonly VCExprOp! Subtype3Op = new VCExprNAryOp (3, Type.Bool); - public static readonly VCExprOp! IfThenElseOp = new VCExprIfThenElseOp(); - - public static readonly VCExprOp! TickleBoolOp = new VCExprCustomOp("tickleBool", 1, Type.Bool); - - public VCExprOp! BoogieFunctionOp(Function! func) { - return new VCExprBoogieFunctionOp(func); - } - - // Bitvector nodes - - public VCExpr! Bitvector(BvConst! bv) { - return Function(new VCExprBvOp(bv.Bits), Integer(bv.Value)); - } - - public VCExpr! BvExtract(VCExpr! bv, int bits, int start, int end) { - return Function(new VCExprBvExtractOp(start, end, bits), bv); - } - - public VCExpr! BvConcat(VCExpr! bv1, VCExpr! bv2) { - return Function(new VCExprBvConcatOp(bv1.Type.BvBits, bv2.Type.BvBits), bv1, bv2); - } - - public VCExpr! AtMost(VCExpr! smaller, VCExpr! greater) { - return Function(SubtypeOp, smaller, greater); - } - - - //////////////////////////////////////////////////////////////////////////////// - // Dispatcher for the visitor - - // the declared singleton operators - internal enum SingletonOp { NotOp, EqOp, NeqOp, AndOp, OrOp, ImpliesOp, - AddOp, SubOp, MulOp, - DivOp, ModOp, LtOp, LeOp, GtOp, GeOp, SubtypeOp, - Subtype3Op, BvConcatOp }; - internal static Dictionary! SingletonOpDict; - - static VCExpressionGenerator() { - SingletonOpDict = new Dictionary (); - SingletonOpDict.Add(NotOp, SingletonOp.NotOp); - SingletonOpDict.Add(EqOp, SingletonOp.EqOp); - SingletonOpDict.Add(NeqOp, SingletonOp.NeqOp); - SingletonOpDict.Add(AndOp, SingletonOp.AndOp); - SingletonOpDict.Add(OrOp, SingletonOp.OrOp); - SingletonOpDict.Add(ImpliesOp, SingletonOp.ImpliesOp); - SingletonOpDict.Add(AddOp, SingletonOp.AddOp); - SingletonOpDict.Add(SubOp, SingletonOp.SubOp); - SingletonOpDict.Add(MulOp, SingletonOp.MulOp); - SingletonOpDict.Add(DivOp, SingletonOp.DivOp); - SingletonOpDict.Add(ModOp, SingletonOp.ModOp); - SingletonOpDict.Add(LtOp, SingletonOp.LtOp); - SingletonOpDict.Add(LeOp, SingletonOp.LeOp); - SingletonOpDict.Add(GtOp, SingletonOp.GtOp); - SingletonOpDict.Add(GeOp, SingletonOp.GeOp); - SingletonOpDict.Add(SubtypeOp, SingletonOp.SubtypeOp); - SingletonOpDict.Add(Subtype3Op,SingletonOp.Subtype3Op); - } - - //////////////////////////////////////////////////////////////////////////////// - - - // Let-bindings - - public VCExprLetBinding! LetBinding(VCExprVar! v, VCExpr! e) { - return new VCExprLetBinding(v, e); - } - - // A "real" let expression. All let-bindings happen simultaneously, i.e., - // at this level the order of the bindings does not matter. It is possible to - // create expressions like "let x = y, y = 5 in ...". All bound variables are - // bound in all bound terms/formulas and can occur there, but the dependencies - // have to be acyclic - public VCExpr! Let(List! bindings, VCExpr! body) { - if (bindings.Count == 0) - // no empty let-bindings - return body; - return new VCExprLet(bindings, body); - } - - public VCExpr! Let(VCExpr! body, params VCExprLetBinding[]! bindings) - requires forall{int i in (0:bindings.Length); bindings[i] != null}; - { - return Let(HelperFuns.ToNonNullList(bindings), body); - } - - - /// - /// In contrast to the previous method, the following methods are not a general LET. - /// Instead, it - /// is a boolean "LET b = P in Q", where P and Q are predicates, that is allowed to be - /// encoded as "(b == P) ==> Q" or even as "(P ==> b) ==> Q" - /// (or "(P ==> b) and Q" in negative positions). - /// The method assumes that the variables in the bindings are unique in the entire formula - /// to be produced, which allows the implementation to ignore scope issues in the event that - /// it needs to generate an alternate expression for LET. - /// - - - // Turn let-bindings let v = E in ... into implications E ==> v - public VCExpr! AsImplications(List! bindings) { - VCExpr! antecedents = True; - foreach (VCExprLetBinding b in bindings) - // turn "LET_binding v = E" into "v <== E" - antecedents = AndSimp(antecedents, Implies(b.E, b.V)); - return antecedents; - } - - // Turn let-bindings let v = E in ... into equations v == E - public VCExpr! AsEquations(List! bindings) { - VCExpr! antecedents = True; - foreach (VCExprLetBinding b in bindings) - // turn "LET_binding v = E" into "v <== E" - antecedents = AndSimp(antecedents, Eq(b.E, b.V)); - return antecedents; - } - - - - // Maps - - public VCExpr! Select(params VCExpr[]! allArgs) - requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; - { - return Function(new VCExprSelectOp(allArgs.Length - 1, 0), - HelperFuns.ToNonNullList(allArgs), - VCExprNAry.EMPTY_TYPE_LIST); - } - - public VCExpr! Select(VCExpr[]! allArgs, Type[]! typeArgs) - requires 1 <= allArgs.Length; - requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; - requires forall{int i in (0:typeArgs.Length); typeArgs[i] != null}; - { - return Function(new VCExprSelectOp(allArgs.Length - 1, typeArgs.Length), - allArgs, typeArgs); - } - - public VCExpr! Select(List! allArgs, List! typeArgs) - requires 1 <= allArgs.Count; - { - return Function(new VCExprSelectOp(allArgs.Count - 1, typeArgs.Count), - allArgs, typeArgs); - } - - public VCExpr! Store(params VCExpr[]! allArgs) - requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; - { - return Function(new VCExprStoreOp(allArgs.Length - 2, 0), - HelperFuns.ToNonNullList(allArgs), - VCExprNAry.EMPTY_TYPE_LIST); - } - - public VCExpr! Store(VCExpr[]! allArgs, Type[]! typeArgs) - requires 2 <= allArgs.Length; - requires forall{int i in (0:allArgs.Length); allArgs[i] != null}; - requires forall{int i in (0:typeArgs.Length); typeArgs[i] != null}; - { - return Function(new VCExprStoreOp(allArgs.Length - 2, typeArgs.Length), - allArgs, typeArgs); - } - - public VCExpr! Store(List! allArgs, List! typeArgs) - requires 2 <= allArgs.Count; - { - return Function(new VCExprStoreOp(allArgs.Count - 2, typeArgs.Count), - allArgs, typeArgs); - } - - - // Labels - - public VCExprLabelOp! LabelOp(bool pos, string! l) { - return new VCExprLabelOp(pos, l); - } - - public VCExpr! LabelNeg(string! label, VCExpr! e) { - if (e.Equals(True)) { - return e; // don't bother putting negative labels around True (which will expose the True to further peephole optimizations) - } - return Function(LabelOp(false, label), e); - } - public VCExpr! LabelPos(string! label, VCExpr! e) { - return Function(LabelOp(true, label), e); - } - - // Quantifiers - - public VCExpr! Quantify(Quantifier quan, - List! typeParams, List! vars, - List! triggers, VCQuantifierInfos! infos, - VCExpr! body) { - return new VCExprQuantifier(quan, typeParams, vars, triggers, infos, body); - } - - public VCExpr! Forall(List! typeParams, List! vars, - List! triggers, VCQuantifierInfos! infos, - VCExpr! body) { - return Quantify(Quantifier.ALL, typeParams, vars, triggers, infos, body); - } - public VCExpr! Forall(List! vars, - List! triggers, - string! qid, VCExpr! body) { - return Quantify(Quantifier.ALL, new List (), vars, - triggers, new VCQuantifierInfos (qid, -1, false, null), body); - } - public VCExpr! Forall(List! vars, - List! triggers, - VCExpr! body) { - return Quantify(Quantifier.ALL, new List (), vars, - triggers, new VCQuantifierInfos (null, -1, false, null), body); - } - public VCExpr! Forall(VCExprVar! var, VCTrigger! trigger, VCExpr! body) { - return Forall(HelperFuns.ToNonNullList(var), HelperFuns.ToNonNullList(trigger), body); - } - public VCExpr! Exists(List! typeParams, List! vars, - List! triggers, VCQuantifierInfos! infos, - VCExpr! body) { - return Quantify(Quantifier.EX, typeParams, vars, triggers, infos, body); - } - public VCExpr! Exists(List! vars, - List! triggers, - VCExpr! body) { - return Quantify(Quantifier.EX, new List (), vars, - triggers, new VCQuantifierInfos (null, -1, false, null), body); - } - public VCExpr! Exists(VCExprVar! var, VCTrigger! trigger, VCExpr! body) { - return Exists(HelperFuns.ToNonNullList(var), HelperFuns.ToNonNullList(trigger), body); - } - - public VCTrigger! Trigger(bool pos, List! exprs) { - return new VCTrigger(pos, exprs); - } - - public VCTrigger! Trigger(bool pos, params VCExpr[]! exprs) - requires forall{int i in (0:exprs.Length); exprs[i] != null}; - { - return Trigger(pos, HelperFuns.ToNonNullList(exprs)); - } - - // Reference to a bound or free variable - - public VCExprVar! Variable(string! name, Type! type) { - return new VCExprVar(name, type); - } - } -} - -namespace Microsoft.Boogie.VCExprAST -{ - - public class HelperFuns { - public static bool SameElements(IEnumerable! a, IEnumerable! b) { - IEnumerator ia = a.GetEnumerator(); - IEnumerator ib = b.GetEnumerator(); - while (true) { - if (ia.MoveNext()) { - if (ib.MoveNext()) { - if (!((!)ia.Current).Equals(ib.Current)) - return false; - } else { - return false; - } - } else { - return !ib.MoveNext(); - } - } - return true; - } - - public static int PolyHash(int init, int factor, IEnumerable! a) { - int res = init; - foreach(object x in a) - res = res * factor + ((!)x).GetHashCode(); - return res; - } - - public static List! ToList(IEnumerable! l) { - List! res = new List (); - foreach (T x in l) - res.Add(x); - return res; - } - - public static TypeSeq! ToTypeSeq(VCExpr[]! exprs, int startIndex) - requires forall{int i in (0:exprs.Length); exprs[i] != null}; - { - TypeSeq! res = new TypeSeq (); - for (int i = startIndex; i < exprs.Length; ++i) - res.Add(((!)exprs[i]).Type); - return res; - } - - public static List! ToNonNullList (params T[]! args) { - List! res = new List (args.Length); - foreach (T t in args) - res.Add((!)t); - return res; - } - - public static IDictionary! Clone(IDictionary! dict) { - IDictionary! res = new Dictionary (dict.Count); - foreach (KeyValuePair pair in dict) - res.Add(pair); - return res; - } - } - - public abstract class VCExpr { - public abstract Type! Type { get; } - - public abstract Result Accept(IVCExprVisitor! visitor, Arg arg); - - [Pure] - public override string! ToString() { - StringWriter! sw = new StringWriter(); - VCExprPrinter! printer = new VCExprPrinter (); - printer.Print(this, sw); - return (!)sw.ToString(); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // Literal expressions - - public class VCExprLiteral : VCExpr { - private readonly Type! LitType; - public override Type! Type { get { return LitType; } } - internal VCExprLiteral(Type! type) { - this.LitType = type; - } - public override Result Accept(IVCExprVisitor! visitor, Arg arg) { - return visitor.Visit(this, arg); - } - } - - public class VCExprIntLit : VCExprLiteral - { - public readonly BigNum Val; - internal VCExprIntLit(BigNum val) { - base(Type.Int); - this.Val = val; - } - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprIntLit) - return Val == ((VCExprIntLit)that).Val; - return false; - } - [Pure] - public override int GetHashCode() { - return Val.GetHashCode() * 72321; - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // Operator expressions with fixed arity - - public abstract class VCExprNAry : VCExpr, IEnumerable { - public readonly VCExprOp! Op; - public int Arity { get { return Op.Arity; } } - public int TypeParamArity { get { return Op.TypeParamArity; } } - public int Length { get { return Arity; } } - // the sub-expressions of the expression - public abstract VCExpr! this[int index] { get; } - - // the type arguments - public abstract List! TypeArguments { get; } - - [Pure] [GlobalAccess(false)] [Escapes(true,false)] - public IEnumerator! GetEnumerator() { - for (int i = 0; i < Arity; ++i) - yield return this[i]; - } - [Pure] [GlobalAccess(false)] [Escapes(true,false)] - IEnumerator! System.Collections.IEnumerable.GetEnumerator() { - for (int i = 0; i < Arity; ++i) - yield return this[i]; - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprNAry) { - // we compare the subterms iteratively (not recursively) - // to avoid stack overflows - - VCExprNAryEnumerator enum0 = new VCExprNAryEnumerator(this); - VCExprNAryEnumerator enum1 = new VCExprNAryEnumerator((VCExprNAry)that); - - while (true) { - bool next0 = enum0.MoveNext(); - bool next1 = enum1.MoveNext(); - if (next0 != next1) - return false; - if (!next0) - return true; - - VCExprNAry nextExprNAry0 = enum0.Current as VCExprNAry; - VCExprNAry nextExprNAry1 = enum1.Current as VCExprNAry; - - if ((nextExprNAry0 == null) != (nextExprNAry1 == null)) - return false; - if (nextExprNAry0 != null && nextExprNAry1 != null) { - if (!nextExprNAry0.Op.Equals(nextExprNAry1.Op)) - return false; - } else { - if (!((!)enum0.Current).Equals(enum1.Current)) - return false; - } - } - } - return false; - } - [Pure] - public override int GetHashCode() { - return HelperFuns.PolyHash(Op.GetHashCode() * 123 + Arity * 61521, - 3, this); - } - - internal VCExprNAry(VCExprOp! op) { - this.Op = op; - } - public override Result Accept(IVCExprVisitor! visitor, Arg arg) { - return visitor.Visit(this, arg); - } - public Result Accept(IVCExprOpVisitor! visitor, Arg arg) { - return Op.Accept(this, visitor, arg); - } - - internal static readonly List! EMPTY_TYPE_LIST = new List (); - internal static readonly List! EMPTY_VCEXPR_LIST = new List (); - } - - // We give specialised implementations for nullary, unary and binary expressions - - internal class VCExprNullary : VCExprNAry { - private readonly Type! ExprType; - public override Type! Type { get { return ExprType; } } - public override VCExpr! this[int index] { get { - assert false; // no arguments - } } - - // the type arguments - public override List! TypeArguments { get { - return EMPTY_TYPE_LIST; - } } - - internal VCExprNullary(VCExprOp! op) - requires op.Arity == 0 && op.TypeParamArity == 0; { - base(op); - this.ExprType = op.InferType(EMPTY_VCEXPR_LIST, EMPTY_TYPE_LIST); - } - } - - internal class VCExprUnary : VCExprNAry { - private readonly VCExpr! Argument; - private readonly Type! ExprType; - public override Type! Type { get { return ExprType; } } - public override VCExpr! this[int index] { get { - assume index == 0; - return Argument; - } } - - // the type arguments - public override List! TypeArguments { get { - return EMPTY_TYPE_LIST; - } } - - internal VCExprUnary(VCExprOp! op, List! arguments) - requires op.Arity == 1 && op.TypeParamArity == 0 && arguments.Count == 1; { - base(op); - this.Argument = arguments[0]; - this.ExprType = - op.InferType(arguments, EMPTY_TYPE_LIST); - } - - internal VCExprUnary(VCExprOp! op, VCExpr! argument) - requires op.Arity == 1 && op.TypeParamArity == 0; { - base(op); - this.Argument = argument; - // PR: could be optimised so that the argument does - // not have to be boxed in an array each time - this.ExprType = - op.InferType(HelperFuns.ToNonNullList(argument), EMPTY_TYPE_LIST); - } - } - - internal class VCExprBinary : VCExprNAry { - private readonly VCExpr! Argument0; - private readonly VCExpr! Argument1; - private readonly Type! ExprType; - public override Type! Type { get { return ExprType; } } - public override VCExpr! this[int index] { get { - switch (index) { - case 0: return Argument0; - case 1: return Argument1; - default: assert false; - } - } } - - // the type arguments - public override List! TypeArguments { get { - return EMPTY_TYPE_LIST; - } } - - internal VCExprBinary(VCExprOp! op, List! arguments) - requires op.Arity == 2 && op.TypeParamArity == 0 && arguments.Count == 2; { - base(op); - this.Argument0 = arguments[0]; - this.Argument1 = arguments[1]; - this.ExprType = op.InferType(arguments, EMPTY_TYPE_LIST); - } - - internal VCExprBinary(VCExprOp! op, VCExpr! argument0, VCExpr! argument1) - requires op.Arity == 2 && op.TypeParamArity == 0; { - base(op); - this.Argument0 = argument0; - this.Argument1 = argument1; - // PR: could be optimised so that the arguments do - // not have to be boxed in an array each time - this.ExprType = - op.InferType(HelperFuns.ToNonNullList(argument0, argument1), - EMPTY_TYPE_LIST); - } - } - - internal class VCExprMultiAry : VCExprNAry { - private readonly List! Arguments; - private readonly List! TypeArgumentsAttr; - - private readonly Type! ExprType; - public override Type! Type { get { return ExprType; } } - public override VCExpr! this[int index] { get { - assume index >= 0 && index < Arity; - return (!)Arguments[index]; - } } - - // the type arguments - public override List! TypeArguments { get { - return TypeArgumentsAttr; - } } - - internal VCExprMultiAry(VCExprOp! op, List! arguments) { - this(op, arguments, EMPTY_TYPE_LIST); - } - internal VCExprMultiAry(VCExprOp! op, List! arguments, List! typeArguments) - requires (arguments.Count > 2 || typeArguments.Count > 0); - requires op.Arity == arguments.Count; - requires op.TypeParamArity == typeArguments.Count; - { - base(op); - this.Arguments = arguments; - this.TypeArgumentsAttr = typeArguments; - this.ExprType = op.InferType(arguments, typeArguments); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // The various operators available - - public abstract class VCExprOp { - // the number of value parameters - public abstract int Arity { get; } - // the number of type parameters - public abstract int TypeParamArity { get; } - - public abstract Type! InferType(List! args, List! typeArgs); - - public virtual Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - VCExpressionGenerator.SingletonOp op; - if (VCExpressionGenerator.SingletonOpDict.TryGetValue(this, out op)) { - switch(op) { - case VCExpressionGenerator.SingletonOp.NotOp: - return visitor.VisitNotOp(expr, arg); - case VCExpressionGenerator.SingletonOp.EqOp: - return visitor.VisitEqOp(expr, arg); - case VCExpressionGenerator.SingletonOp.NeqOp: - return visitor.VisitNeqOp(expr, arg); - case VCExpressionGenerator.SingletonOp.AndOp: - return visitor.VisitAndOp(expr, arg); - case VCExpressionGenerator.SingletonOp.OrOp: - return visitor.VisitOrOp(expr, arg); - case VCExpressionGenerator.SingletonOp.ImpliesOp: - return visitor.VisitImpliesOp(expr, arg); - case VCExpressionGenerator.SingletonOp.AddOp: - return visitor.VisitAddOp(expr, arg); - case VCExpressionGenerator.SingletonOp.SubOp: - return visitor.VisitSubOp(expr, arg); - case VCExpressionGenerator.SingletonOp.MulOp: - return visitor.VisitMulOp(expr, arg); - case VCExpressionGenerator.SingletonOp.DivOp: - return visitor.VisitDivOp(expr, arg); - case VCExpressionGenerator.SingletonOp.ModOp: - return visitor.VisitModOp(expr, arg); - case VCExpressionGenerator.SingletonOp.LtOp: - return visitor.VisitLtOp(expr, arg); - case VCExpressionGenerator.SingletonOp.LeOp: - return visitor.VisitLeOp(expr, arg); - case VCExpressionGenerator.SingletonOp.GtOp: - return visitor.VisitGtOp(expr, arg); - case VCExpressionGenerator.SingletonOp.GeOp: - return visitor.VisitGeOp(expr, arg); - case VCExpressionGenerator.SingletonOp.SubtypeOp: - return visitor.VisitSubtypeOp(expr, arg); - case VCExpressionGenerator.SingletonOp.Subtype3Op: - return visitor.VisitSubtype3Op(expr, arg); - case VCExpressionGenerator.SingletonOp.BvConcatOp: - return visitor.VisitBvConcatOp(expr, arg); - default: - assert false; - } - } else { - assert false; - } - } - } - - public class VCExprNAryOp : VCExprOp { - private readonly Type! OpType; - private readonly int OpArity; - - public override int Arity { get { return OpArity; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return OpType; - } - - internal VCExprNAryOp(int arity, Type! type) { - this.OpArity = arity; - this.OpType = type; - } - } - - public class VCExprDistinctOp : VCExprNAryOp { - internal VCExprDistinctOp(int arity) { - base(arity, Type.Bool); - } - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprDistinctOp) - return Arity == ((VCExprDistinctOp)that).Arity; - return false; - } - [Pure] - public override int GetHashCode() { - return Arity * 917632481; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitDistinctOp(expr, arg); - } - } - - public class VCExprLabelOp : VCExprOp { - public override int Arity { get { return 1; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return args[0].Type; - } - - public readonly bool pos; - public readonly string! label; - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprLabelOp) { - VCExprLabelOp! thatOp = (VCExprLabelOp)that; - return this.pos == thatOp.pos && this.label.Equals(thatOp.label); - } - return false; - } - [Pure] - public override int GetHashCode() { - return (pos ? 9817231 : 7198639) + label.GetHashCode(); - } - - internal VCExprLabelOp(bool pos, string! l) { - this.pos = pos; - this.label = pos ? "+" + l : "@" + l; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitLabelOp(expr, arg); - } - } - - public class VCExprSelectOp : VCExprOp { - private readonly int MapArity; - private readonly int MapTypeParamArity; - public override int Arity { get { return MapArity + 1; } } - public override int TypeParamArity { get { return MapTypeParamArity; } } - - public override Type! InferType(List! args, List! typeArgs) { - MapType! mapType = args[0].Type.AsMap; - assert TypeParamArity == mapType.TypeParameters.Length; - IDictionary! subst = new Dictionary (); - for (int i = 0; i < TypeParamArity; ++i) - subst.Add(mapType.TypeParameters[i], typeArgs[i]); - return mapType.Result.Substitute(subst); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprSelectOp) - return Arity == ((VCExprSelectOp)that).Arity && - TypeParamArity == ((VCExprSelectOp)that).TypeParamArity; - return false; - } - [Pure] - public override int GetHashCode() { - return Arity * 1212481 + TypeParamArity * 298741; - } - - internal VCExprSelectOp(int arity, int typeParamArity) - requires 0 <= arity && 0 <= typeParamArity; - { - this.MapArity = arity; - this.MapTypeParamArity = typeParamArity; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitSelectOp(expr, arg); - } - } - - public class VCExprStoreOp : VCExprOp { - private readonly int MapArity; - private readonly int MapTypeParamArity; - public override int Arity { get { return MapArity + 2; } } - // stores never need explicit type parameters, because also the - // rhs is a value argument - public override int TypeParamArity { get { return MapTypeParamArity; } } - - public override Type! InferType(List! args, List! typeArgs) { - return args[0].Type; - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprStoreOp) - return Arity == ((VCExprStoreOp)that).Arity; - return false; - } - [Pure] - public override int GetHashCode() { - return Arity * 91361821; - } - - internal VCExprStoreOp(int arity, int typeParamArity) - requires 0 <= arity && 0 <= typeParamArity; - { - this.MapArity = arity; - this.MapTypeParamArity = typeParamArity; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitStoreOp(expr, arg); - } - } - - public class VCExprIfThenElseOp : VCExprOp { - public override int Arity { get { return 3; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return args[1].Type; - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprIfThenElseOp) - return true; - return false; - } - [Pure] - public override int GetHashCode() { - return 1; - } - - internal VCExprIfThenElseOp() { - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitIfThenElseOp(expr, arg); - } - } - - public class VCExprCustomOp : VCExprOp { - public readonly string! Name; - int arity; - public readonly Type! Type; - public VCExprCustomOp(string! name, int arity, Type! type) { - this.Name = name; - this.arity = arity; - this.Type = type; - } - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - VCExprCustomOp t = that as VCExprCustomOp; - if (t == null) - return false; - return this.Name == t.Name && this.arity == t.arity && this.Type == t.Type; - } - public override int Arity { get { return arity; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { return Type; } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitCustomOp(expr, arg); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // Bitvector operators - - public class VCExprBvOp : VCExprOp { - public readonly int Bits; - - public override int Arity { get { return 1; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return Type.GetBvType(Bits); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprBvOp) - return this.Bits == ((VCExprBvOp)that).Bits; - return false; - } - [Pure] - public override int GetHashCode() { - return Bits * 81748912; - } - - internal VCExprBvOp(int bits) { - this.Bits = bits; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitBvOp(expr, arg); - } - } - - public class VCExprBvExtractOp : VCExprOp { - public readonly int Start; - public readonly int End; - public readonly int Total; // the number of bits from which the End-Start bits are extracted - - public override int Arity { get { return 1; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return Type.GetBvType(End - Start); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprBvExtractOp) { - VCExprBvExtractOp! thatExtract = (VCExprBvExtractOp)that; - return this.Start == thatExtract.Start && this.End == thatExtract.End && this.Total == thatExtract.Total; - } - return false; - } - [Pure] - public override int GetHashCode() { - return Start * 81912 + End * 978132 + Total * 571289; - } - - internal VCExprBvExtractOp(int start, int end, int total) - requires 0 <= start && start <= end && end <= total; - { - this.Start = start; - this.End = end; - this.Total = total; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitBvExtractOp(expr, arg); - } - } - - public class VCExprBvConcatOp : VCExprOp { - public readonly int LeftSize; - public readonly int RightSize; - - public override int Arity { get { return 2; } } - public override int TypeParamArity { get { return 0; } } - public override Type! InferType(List! args, List! typeArgs) { - return Type.GetBvType(args[0].Type.BvBits + args[1].Type.BvBits); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprBvConcatOp) { - VCExprBvConcatOp thatConcat = (VCExprBvConcatOp)that; - return this.LeftSize == thatConcat.LeftSize && this.RightSize == thatConcat.RightSize; - } - return false; - } - [Pure] - public override int GetHashCode() { - return LeftSize * 81912 + RightSize * 978132; - } - - internal VCExprBvConcatOp(int leftSize, int rightSize) - requires 0 <= leftSize && 0 <= rightSize; - { - this.LeftSize = leftSize; - this.RightSize = rightSize; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitBvConcatOp(expr, arg); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // References to user-defined Boogie functions - - public class VCExprBoogieFunctionOp : VCExprOp { - public readonly Function! Func; - - public override int Arity { get { return Func.InParams.Length; } } - public override int TypeParamArity { get { return Func.TypeParameters.Length; } } - public override Type! InferType(List! args, List! typeArgs) { - assert TypeParamArity == Func.TypeParameters.Length; - if (TypeParamArity == 0) - return ((!)Func.OutParams[0]).TypedIdent.Type; - IDictionary! subst = new Dictionary (TypeParamArity); - for (int i = 0; i < TypeParamArity; ++i) - subst.Add(Func.TypeParameters[i], typeArgs[i]); - return ((!)Func.OutParams[0]).TypedIdent.Type.Substitute(subst); - } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprBoogieFunctionOp) - return this.Func.Equals(((VCExprBoogieFunctionOp)that).Func); - return false; - } - [Pure] - public override int GetHashCode() { - return Func.GetHashCode() + 18731; - } - - // we require that the result type of the expression is specified, because we - // do not want to perform full type inference at this point - internal VCExprBoogieFunctionOp(Function! func) { - this.Func = func; - } - public override Result Accept - (VCExprNAry! expr, IVCExprOpVisitor! visitor, Arg arg) { - return visitor.VisitBoogieFunctionOp(expr, arg); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // Binders (quantifiers and let-expressions). We introduce our own class for - // term variables, but use the Boogie-AST class for type variables - - public class VCExprVar : VCExpr { - // the name of the variable. Note that the name is not used for comparison, - // i.e., there can be two distinct variables with the same name - public readonly string! Name; - private readonly Type! VarType; - public override Type! Type { get { return VarType; } } - - internal VCExprVar(string! name, Type! type) { - this.Name = name; - this.VarType = type; - } - public override Result Accept(IVCExprVisitor! visitor, Arg arg) { - return visitor.Visit(this, arg); - } - } - - public abstract class VCExprBinder : VCExpr { - public readonly VCExpr! Body; - public readonly List! TypeParameters; - public readonly List! BoundVars; - - public override Type! Type { get { return Body.Type; } } - - internal VCExprBinder(List! typeParams, - List! boundVars, - VCExpr! body) - requires boundVars.Count + typeParams.Count > 0; { // only nontrivial binders ... - this.TypeParameters = typeParams; - this.BoundVars = boundVars; - this.Body = body; - } - } - - public class VCTrigger { - public readonly bool Pos; - public readonly List! Exprs; - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCTrigger) { - VCTrigger! thatTrigger = (VCTrigger)that; - return this.Pos == thatTrigger.Pos && - HelperFuns.SameElements(this.Exprs, thatTrigger.Exprs); - } - return false; - } - [Pure] - public override int GetHashCode() { - return (Pos ? 913821 : 871334) + - HelperFuns.PolyHash(123, 7, this.Exprs); - } - - public VCTrigger(bool pos, List! exprs) { - this.Pos = pos; - this.Exprs = exprs; - } - } - - public class VCQuantifierInfos { - public readonly string qid; - public readonly int uniqueId; - public readonly bool bvZ3Native; - public QKeyValue attributes; - - public VCQuantifierInfos(string qid, int uniqueId, bool bvZ3Native, QKeyValue attributes) { - this.qid = qid; - this.uniqueId = uniqueId; - this.bvZ3Native = bvZ3Native; - this.attributes = attributes; - } - } - - public enum Quantifier { ALL, EX }; - - public class VCExprQuantifier : VCExprBinder { - public readonly Quantifier Quan; - - public readonly List! Triggers; - public readonly VCQuantifierInfos! Infos; - - // Equality is /not/ modulo bound renaming at this point - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprQuantifier) { - VCExprQuantifier! thatQuan = (VCExprQuantifier)that; - return this.Quan == thatQuan.Quan && - HelperFuns.SameElements(this.Triggers, thatQuan.Triggers) && - HelperFuns.SameElements(this.TypeParameters, thatQuan.TypeParameters) && - HelperFuns.SameElements(this.BoundVars, thatQuan.BoundVars) && - this.Body.Equals(thatQuan.Body); - } - return false; - } - [Pure] - public override int GetHashCode() { - return Quan.GetHashCode() + - HelperFuns.PolyHash(973219, 7, TypeParameters) + - HelperFuns.PolyHash(998431, 9, BoundVars) + - HelperFuns.PolyHash(123, 11, Triggers); - } - - internal VCExprQuantifier(Quantifier kind, - List! typeParams, - List! boundVars, - List! triggers, - VCQuantifierInfos! infos, - VCExpr! body) { - base(typeParams, boundVars, body); - this.Quan = kind; - this.Triggers = triggers; - this.Infos = infos; - } - public override Result Accept(IVCExprVisitor! visitor, Arg arg) { - return visitor.Visit(this, arg); - } - } - - ///////////////////////////////////////////////////////////////////////////////// - // Let-Bindings - - public class VCExprLetBinding { - public readonly VCExprVar! V; - public readonly VCExpr! E; - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprLetBinding) { - VCExprLetBinding! thatB = (VCExprLetBinding)that; - return this.V.Equals(thatB.V) && this.E.Equals(thatB.E); - } - return false; - } - [Pure] - public override int GetHashCode() { - return V.GetHashCode() * 71261 + E.GetHashCode(); - } - - internal VCExprLetBinding(VCExprVar! v, VCExpr! e) { - this.V = v; - this.E = e; - assert v.Type.Equals(e.Type); - } - } - - public class VCExprLet : VCExprBinder, IEnumerable { - private readonly List! Bindings; - - public int Length { get { return Bindings.Count; } } - public VCExprLetBinding! this[int index] { get { - return Bindings[index]; - } } - - [Pure][Reads(ReadsAttribute.Reads.Nothing)] - public override bool Equals(object that) { - if (Object.ReferenceEquals(this, that)) - return true; - if (that is VCExprLet) { - VCExprLet! thatLet = (VCExprLet)that; - return this.Body.Equals(thatLet.Body) && - HelperFuns.SameElements(this, (VCExprLet)that); - } - return false; - } - [Pure] - public override int GetHashCode() { - return HelperFuns.PolyHash(Body.GetHashCode(), 9, Bindings); - } - - [Pure] [GlobalAccess(false)] [Escapes(true,false)] - public IEnumerator! GetEnumerator() { - return Bindings.GetEnumerator(); - } - [Pure] [GlobalAccess(false)] [Escapes(true,false)] - IEnumerator! System.Collections.IEnumerable.GetEnumerator() { - return Bindings.GetEnumerator(); - } - - private static List! toSeq(List! bindings) { - List! res = new List (); - foreach (VCExprLetBinding! b in bindings) - res.Add(b.V); - return res; - } - - internal VCExprLet(List! bindings, - VCExpr! body) { - base(new List (), toSeq(bindings), body); - this.Bindings = bindings; - } - public override Result Accept(IVCExprVisitor! visitor, Arg arg) { - return visitor.Visit(this, arg); - } - } -} diff --git a/Source/VCExpr/VCExprASTPrinter.cs b/Source/VCExpr/VCExprASTPrinter.cs new file mode 100644 index 00000000..796a2b4e --- /dev/null +++ b/Source/VCExpr/VCExprASTPrinter.cs @@ -0,0 +1,247 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// A simple visitor for turning a VCExpr into a human-readable string +// (S-expr syntax) + +namespace Microsoft.Boogie.VCExprAST +{ + + public class VCExprPrinter : IVCExprVisitor { + private VCExprOpPrinter OpPrinterVar = null; + private VCExprOpPrinter! OpPrinter { get { + if (OpPrinterVar == null) + OpPrinterVar = new VCExprOpPrinter(this); + return OpPrinterVar; + } } + + public void Print(VCExpr! expr, TextWriter! wr) { + expr.Accept(this, wr); + } + + public bool Visit(VCExprLiteral! node, TextWriter! wr) { + if (node == VCExpressionGenerator.True) + wr.Write("true"); + else if (node == VCExpressionGenerator.False) + wr.Write("false"); + else if (node is VCExprIntLit) { + wr.Write(((VCExprIntLit)node).Val); + } else + assert false; + return true; + } + public bool Visit(VCExprNAry! node, TextWriter! wr) { + VCExprOp! op = node.Op; + + if (op.Equals(VCExpressionGenerator.AndOp) || + op.Equals(VCExpressionGenerator.OrOp)) { + // handle these operators without recursion + + wr.Write("({0}", + op.Equals(VCExpressionGenerator.AndOp) ? "And" : "Or"); + IEnumerator! enumerator = new VCExprNAryUniformOpEnumerator (node); + while (enumerator.MoveNext()) { + VCExprNAry naryExpr = enumerator.Current as VCExprNAry; + if (naryExpr == null || !naryExpr.Op.Equals(op)) { + wr.Write(" "); + Print((VCExpr!)enumerator.Current, wr); + } + } + + wr.Write(")"); + + return true; + } + + return node.Accept(OpPrinter, wr); + } + public bool Visit(VCExprVar! node, TextWriter! wr) { + wr.Write(node.Name); + return true; + } + public bool Visit(VCExprQuantifier! node, TextWriter! wr) { + string! quan = node.Quan == Quantifier.ALL ? "Forall" : "Exists"; + + wr.Write("({0} ", quan); + + if (node.TypeParameters.Count > 0) { + wr.Write("<"); + string! sep = ""; + foreach (TypeVariable! v in node.TypeParameters) { + wr.Write(sep); + sep = ", "; + wr.Write("{0}", v.Name); + } + wr.Write("> "); + } + + if (node.BoundVars.Count > 0) { + string! sep = ""; + foreach (VCExprVar! v in node.BoundVars) { + wr.Write(sep); + sep = ", "; + Print(v, wr); + } + wr.Write(" "); + } + + wr.Write(":: "); + + if (node.Triggers.Count > 0) { + wr.Write("{0} ", "{"); + string! sep = ""; + foreach (VCTrigger! t in node.Triggers) { + wr.Write(sep); + sep = ", "; + string! sep2 = ""; + foreach (VCExpr! e in t.Exprs) { + wr.Write(sep2); + sep2 = "+"; + Print(e, wr); + } + } + wr.Write(" {0} ", "}"); + } + + Print(node.Body, wr); + wr.Write(")"); + return true; + } + public bool Visit(VCExprLet! node, TextWriter! wr) { + wr.Write("(Let "); + + string! sep = ""; + foreach (VCExprLetBinding! b in node) { + wr.Write(sep); + sep = ", "; + Print(b.V, wr); + wr.Write(" = "); + Print(b.E, wr); + } + wr.Write(" "); + + Print(node.Body, wr); + wr.Write(")"); + return true; + } + } + + public class VCExprOpPrinter : IVCExprOpVisitor { + private VCExprPrinter! ExprPrinter; + + public VCExprOpPrinter(VCExprPrinter! exprPrinter) { + this.ExprPrinter = exprPrinter; + } + + private bool PrintNAry(string! op, VCExprNAry! node, TextWriter! wr) { + wr.Write("({0}", op); + foreach (VCExpr! arg in node) { + wr.Write(" "); + ExprPrinter.Print(arg, wr); + } + wr.Write(")"); + return true; + } + + public bool VisitNotOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("!", node, wr); + } + public bool VisitEqOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("==", node, wr); + } + public bool VisitNeqOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("!=", node, wr); + } + public bool VisitAndOp (VCExprNAry! node, TextWriter! wr) { + assert false; + } + public bool VisitOrOp (VCExprNAry! node, TextWriter! wr) { + assert false; + } + public bool VisitImpliesOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("Implies", node, wr); + } + public bool VisitDistinctOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("Distinct", node, wr); + } + public bool VisitLabelOp (VCExprNAry! node, TextWriter! wr) { + VCExprLabelOp! op = (VCExprLabelOp)node.Op; + return PrintNAry("Label " + op.label, node, wr); + } + public bool VisitSelectOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("Select", node, wr); + } + public bool VisitStoreOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("Store", node, wr); + } + public bool VisitBvOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("Bv", node, wr); + } + public bool VisitBvExtractOp(VCExprNAry! node, TextWriter! wr) { + return PrintNAry("BvExtract", node, wr); + } + public bool VisitBvConcatOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("BvConcat", node, wr); + } + public bool VisitIfThenElseOp(VCExprNAry! node, TextWriter! wr) { + return PrintNAry("if-then-else", node, wr); + } + public bool VisitCustomOp(VCExprNAry! node, TextWriter! wr) { + VCExprCustomOp op = (VCExprCustomOp)node.Op; + return PrintNAry(op.Name, node, wr); + } + public bool VisitAddOp (VCExprNAry! node, TextWriter! wr) { + if (CommandLineOptions.Clo.ReflectAdd) { + return PrintNAry("Reflect$Add", node, wr); + } else { + return PrintNAry("+", node, wr); + } + } + public bool VisitSubOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("-", node, wr); + } + public bool VisitMulOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("*", node, wr); + } + public bool VisitDivOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("/", node, wr); + } + public bool VisitModOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("%", node, wr); + } + public bool VisitLtOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("<", node, wr); + } + public bool VisitLeOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("<=", node, wr); + } + public bool VisitGtOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry(">", node, wr); + } + public bool VisitGeOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry(">=", node, wr); + } + public bool VisitSubtypeOp (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("<:", node, wr); + } + public bool VisitSubtype3Op (VCExprNAry! node, TextWriter! wr) { + return PrintNAry("<::", node, wr); + } + public bool VisitBoogieFunctionOp (VCExprNAry! node, TextWriter! wr) { + VCExprBoogieFunctionOp! op = (VCExprBoogieFunctionOp)node.Op; + return PrintNAry(op.Func.Name, node, wr); + } + } + + +} diff --git a/Source/VCExpr/VCExprASTPrinter.ssc b/Source/VCExpr/VCExprASTPrinter.ssc deleted file mode 100644 index 796a2b4e..00000000 --- a/Source/VCExpr/VCExprASTPrinter.ssc +++ /dev/null @@ -1,247 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// A simple visitor for turning a VCExpr into a human-readable string -// (S-expr syntax) - -namespace Microsoft.Boogie.VCExprAST -{ - - public class VCExprPrinter : IVCExprVisitor { - private VCExprOpPrinter OpPrinterVar = null; - private VCExprOpPrinter! OpPrinter { get { - if (OpPrinterVar == null) - OpPrinterVar = new VCExprOpPrinter(this); - return OpPrinterVar; - } } - - public void Print(VCExpr! expr, TextWriter! wr) { - expr.Accept(this, wr); - } - - public bool Visit(VCExprLiteral! node, TextWriter! wr) { - if (node == VCExpressionGenerator.True) - wr.Write("true"); - else if (node == VCExpressionGenerator.False) - wr.Write("false"); - else if (node is VCExprIntLit) { - wr.Write(((VCExprIntLit)node).Val); - } else - assert false; - return true; - } - public bool Visit(VCExprNAry! node, TextWriter! wr) { - VCExprOp! op = node.Op; - - if (op.Equals(VCExpressionGenerator.AndOp) || - op.Equals(VCExpressionGenerator.OrOp)) { - // handle these operators without recursion - - wr.Write("({0}", - op.Equals(VCExpressionGenerator.AndOp) ? "And" : "Or"); - IEnumerator! enumerator = new VCExprNAryUniformOpEnumerator (node); - while (enumerator.MoveNext()) { - VCExprNAry naryExpr = enumerator.Current as VCExprNAry; - if (naryExpr == null || !naryExpr.Op.Equals(op)) { - wr.Write(" "); - Print((VCExpr!)enumerator.Current, wr); - } - } - - wr.Write(")"); - - return true; - } - - return node.Accept(OpPrinter, wr); - } - public bool Visit(VCExprVar! node, TextWriter! wr) { - wr.Write(node.Name); - return true; - } - public bool Visit(VCExprQuantifier! node, TextWriter! wr) { - string! quan = node.Quan == Quantifier.ALL ? "Forall" : "Exists"; - - wr.Write("({0} ", quan); - - if (node.TypeParameters.Count > 0) { - wr.Write("<"); - string! sep = ""; - foreach (TypeVariable! v in node.TypeParameters) { - wr.Write(sep); - sep = ", "; - wr.Write("{0}", v.Name); - } - wr.Write("> "); - } - - if (node.BoundVars.Count > 0) { - string! sep = ""; - foreach (VCExprVar! v in node.BoundVars) { - wr.Write(sep); - sep = ", "; - Print(v, wr); - } - wr.Write(" "); - } - - wr.Write(":: "); - - if (node.Triggers.Count > 0) { - wr.Write("{0} ", "{"); - string! sep = ""; - foreach (VCTrigger! t in node.Triggers) { - wr.Write(sep); - sep = ", "; - string! sep2 = ""; - foreach (VCExpr! e in t.Exprs) { - wr.Write(sep2); - sep2 = "+"; - Print(e, wr); - } - } - wr.Write(" {0} ", "}"); - } - - Print(node.Body, wr); - wr.Write(")"); - return true; - } - public bool Visit(VCExprLet! node, TextWriter! wr) { - wr.Write("(Let "); - - string! sep = ""; - foreach (VCExprLetBinding! b in node) { - wr.Write(sep); - sep = ", "; - Print(b.V, wr); - wr.Write(" = "); - Print(b.E, wr); - } - wr.Write(" "); - - Print(node.Body, wr); - wr.Write(")"); - return true; - } - } - - public class VCExprOpPrinter : IVCExprOpVisitor { - private VCExprPrinter! ExprPrinter; - - public VCExprOpPrinter(VCExprPrinter! exprPrinter) { - this.ExprPrinter = exprPrinter; - } - - private bool PrintNAry(string! op, VCExprNAry! node, TextWriter! wr) { - wr.Write("({0}", op); - foreach (VCExpr! arg in node) { - wr.Write(" "); - ExprPrinter.Print(arg, wr); - } - wr.Write(")"); - return true; - } - - public bool VisitNotOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("!", node, wr); - } - public bool VisitEqOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("==", node, wr); - } - public bool VisitNeqOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("!=", node, wr); - } - public bool VisitAndOp (VCExprNAry! node, TextWriter! wr) { - assert false; - } - public bool VisitOrOp (VCExprNAry! node, TextWriter! wr) { - assert false; - } - public bool VisitImpliesOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("Implies", node, wr); - } - public bool VisitDistinctOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("Distinct", node, wr); - } - public bool VisitLabelOp (VCExprNAry! node, TextWriter! wr) { - VCExprLabelOp! op = (VCExprLabelOp)node.Op; - return PrintNAry("Label " + op.label, node, wr); - } - public bool VisitSelectOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("Select", node, wr); - } - public bool VisitStoreOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("Store", node, wr); - } - public bool VisitBvOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("Bv", node, wr); - } - public bool VisitBvExtractOp(VCExprNAry! node, TextWriter! wr) { - return PrintNAry("BvExtract", node, wr); - } - public bool VisitBvConcatOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("BvConcat", node, wr); - } - public bool VisitIfThenElseOp(VCExprNAry! node, TextWriter! wr) { - return PrintNAry("if-then-else", node, wr); - } - public bool VisitCustomOp(VCExprNAry! node, TextWriter! wr) { - VCExprCustomOp op = (VCExprCustomOp)node.Op; - return PrintNAry(op.Name, node, wr); - } - public bool VisitAddOp (VCExprNAry! node, TextWriter! wr) { - if (CommandLineOptions.Clo.ReflectAdd) { - return PrintNAry("Reflect$Add", node, wr); - } else { - return PrintNAry("+", node, wr); - } - } - public bool VisitSubOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("-", node, wr); - } - public bool VisitMulOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("*", node, wr); - } - public bool VisitDivOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("/", node, wr); - } - public bool VisitModOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("%", node, wr); - } - public bool VisitLtOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("<", node, wr); - } - public bool VisitLeOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("<=", node, wr); - } - public bool VisitGtOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry(">", node, wr); - } - public bool VisitGeOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry(">=", node, wr); - } - public bool VisitSubtypeOp (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("<:", node, wr); - } - public bool VisitSubtype3Op (VCExprNAry! node, TextWriter! wr) { - return PrintNAry("<::", node, wr); - } - public bool VisitBoogieFunctionOp (VCExprNAry! node, TextWriter! wr) { - VCExprBoogieFunctionOp! op = (VCExprBoogieFunctionOp)node.Op; - return PrintNAry(op.Func.Name, node, wr); - } - } - - -} diff --git a/Source/VCExpr/VCExprASTVisitors.cs b/Source/VCExpr/VCExprASTVisitors.cs new file mode 100644 index 00000000..c9d56962 --- /dev/null +++ b/Source/VCExpr/VCExprASTVisitors.cs @@ -0,0 +1,1006 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Contracts; +using Microsoft.Basetypes; + +// Some visitor skeletons for the VCExpression AST + +namespace Microsoft.Boogie.VCExprAST +{ + using Microsoft.Boogie; + + public interface IVCExprVisitor { + Result Visit(VCExprLiteral! node, Arg arg); + Result Visit(VCExprNAry! node, Arg arg); + Result Visit(VCExprVar! node, Arg arg); + Result Visit(VCExprQuantifier! node, Arg arg); + Result Visit(VCExprLet! node, Arg arg); + } + + public interface IVCExprOpVisitor { + Result VisitNotOp (VCExprNAry! node, Arg arg); + Result VisitEqOp (VCExprNAry! node, Arg arg); + Result VisitNeqOp (VCExprNAry! node, Arg arg); + Result VisitAndOp (VCExprNAry! node, Arg arg); + Result VisitOrOp (VCExprNAry! node, Arg arg); + Result VisitImpliesOp (VCExprNAry! node, Arg arg); + Result VisitDistinctOp (VCExprNAry! node, Arg arg); + Result VisitLabelOp (VCExprNAry! node, Arg arg); + Result VisitSelectOp (VCExprNAry! node, Arg arg); + Result VisitStoreOp (VCExprNAry! node, Arg arg); + Result VisitBvOp (VCExprNAry! node, Arg arg); + Result VisitBvExtractOp(VCExprNAry! node, Arg arg); + Result VisitBvConcatOp (VCExprNAry! node, Arg arg); + Result VisitAddOp (VCExprNAry! node, Arg arg); + Result VisitSubOp (VCExprNAry! node, Arg arg); + Result VisitMulOp (VCExprNAry! node, Arg arg); + Result VisitDivOp (VCExprNAry! node, Arg arg); + Result VisitModOp (VCExprNAry! node, Arg arg); + Result VisitLtOp (VCExprNAry! node, Arg arg); + Result VisitLeOp (VCExprNAry! node, Arg arg); + Result VisitGtOp (VCExprNAry! node, Arg arg); + Result VisitGeOp (VCExprNAry! node, Arg arg); + Result VisitSubtypeOp (VCExprNAry! node, Arg arg); + Result VisitSubtype3Op (VCExprNAry! node, Arg arg); + Result VisitBoogieFunctionOp (VCExprNAry! node, Arg arg); + Result VisitIfThenElseOp (VCExprNAry! node, Arg arg); + Result VisitCustomOp (VCExprNAry! node, Arg arg); + } + + ////////////////////////////////////////////////////////////////////////////// + // Standard implementations that make it easier to create own visitors + + // Simple traversal of VCExprs. The Visit implementations work + // recursively, apart from the implementation for VCExprNAry that + // uses a stack when applied to nested nodes with the same + // operator, e.g., (AND (AND (AND ...) ...) ...). This is necessary + // to avoid stack overflows + + public abstract class TraversingVCExprVisitor + : IVCExprVisitor { + protected abstract Result StandardResult(VCExpr! node, Arg arg); + + public Result Traverse(VCExpr! node, Arg arg) { + return node.Accept(this, arg); + } + + public virtual Result Visit(VCExprLiteral! node, Arg arg) { + return StandardResult(node, arg); + } + + public virtual Result Visit(VCExprNAry! node, Arg arg) { + Result res = StandardResult(node, arg); + + if (node.TypeParamArity == 0) { + VCExprOp! op = node.Op; + + IEnumerator enumerator = new VCExprNAryUniformOpEnumerator(node); + enumerator.MoveNext(); // skip the node itself + + while (enumerator.MoveNext()) { + VCExpr! expr = (VCExpr!)enumerator.Current; + VCExprNAry naryExpr = expr as VCExprNAry; + if (naryExpr == null || !naryExpr.Op.Equals(op)) { + expr.Accept(this, arg); + } else { + StandardResult(expr, arg); + } + } + } else { + foreach (VCExpr! e in node) + e.Accept(this, arg); + } + + return res; + } + + public virtual Result Visit(VCExprVar! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result Visit(VCExprQuantifier! node, Arg arg) { + Result res = StandardResult(node, arg); + foreach (VCTrigger! trigger in node.Triggers) + foreach (VCExpr! expr in trigger.Exprs) + expr.Accept(this, arg); + node.Body.Accept(this, arg); + return res; + } + public virtual Result Visit(VCExprLet! node, Arg arg) { + Result res = StandardResult(node, arg); + // visit the bound expressions first + foreach (VCExprLetBinding! binding in node) + binding.E.Accept(this, arg); + node.Body.Accept(this, arg); + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + // Class to iterate over the nodes of a tree of VCExprNAry. This is + // used to avoid handling such VCExpr recursively, which can easily + // lead to stack overflows + + public class VCExprNAryEnumerator : IEnumerator { + + private readonly VCExprNAry! CompleteExpr; + private VCExpr CurrentExpr = null; + private readonly Stack! ExprTodo = new Stack (); + + public VCExprNAryEnumerator(VCExprNAry! completeExpr) { + this.CompleteExpr = completeExpr; + Stack! exprTodo = new Stack (); + exprTodo.Push(completeExpr); + ExprTodo = exprTodo; + } + + // Method using which a subclass can decide whether the + // subexpressions of an expression should be enumerated as well + // The default is to enumerate all nodes + protected virtual bool Descend(VCExprNAry! expr) { + return true; + } + + //////////////////////////////////////////////////////////////////////////// + + public bool MoveNext() { + if (ExprTodo.Count == 0) + return false; + + CurrentExpr = ExprTodo.Pop(); + VCExprNAry currentNAry = CurrentExpr as VCExprNAry; + if (currentNAry != null && Descend(currentNAry)) { + for (int i = currentNAry.Arity - 1; i >= 0; --i) + ExprTodo.Push(currentNAry[i]); + } + + return true; + } + + public object Current { + get { + return (!)CurrentExpr; + } } + + public void Reset() { + ExprTodo.Clear(); + CurrentExpr = null; + ExprTodo.Push(CompleteExpr); + } + } + + + ////////////////////////////////////////////////////////////////////////////// + + public class VCExprNAryUniformOpEnumerator : VCExprNAryEnumerator { + private readonly VCExprOp! Op; + public VCExprNAryUniformOpEnumerator(VCExprNAry! completeExpr) { + base(completeExpr); + this.Op = completeExpr.Op; + } + protected override bool Descend(VCExprNAry! expr) { + return expr.Op.Equals(Op) && + // we never skip nodes with type parameters + // (those are too interesting ...) + expr.TypeParamArity == 0; + } + } + + ////////////////////////////////////////////////////////////////////////////// + // Visitor that knows about the variables bound at each location in a VCExpr + + public abstract class BoundVarTraversingVCExprVisitor + : TraversingVCExprVisitor { + // Maps with all variables bound above a certain location in the VCExpression. + // The value of the map tells how often a particular symbol was bound + private readonly IDictionary! BoundTermVarsDict = + new Dictionary (); + private readonly IDictionary! BoundTypeVarsDict = + new Dictionary (); + + protected ICollection! BoundTermVars { get { + return BoundTermVarsDict.Keys; + } } + protected ICollection! BoundTypeVars { get { + return BoundTypeVarsDict.Keys; + } } + + private void AddBoundVar(IDictionary! dict, T! sym) { + int n; + if (dict.TryGetValue(sym, out n)) + dict[sym] = n + 1; + else + dict[sym] = 1; + } + + private void RemoveBoundVar(IDictionary! dict, T! sym) { + int n; + bool b = dict.TryGetValue(sym, out n); + assert b && n > 0; + if (n == 1) + dict.Remove(sym); + else + dict[sym] = n - 1; + } + + public override Result Visit(VCExprQuantifier! node, Arg arg) { + // we temporarily add bound (term and type) variables to the + // corresponding lists + foreach (VCExprVar! v in node.BoundVars) + AddBoundVar(BoundTermVarsDict, v); + foreach (TypeVariable! v in node.TypeParameters) + AddBoundVar(BoundTypeVarsDict, v); + + Result res; + try { + res = VisitAfterBinding(node, arg); + } finally { + foreach (VCExprVar! v in node.BoundVars) + RemoveBoundVar(BoundTermVarsDict, v); + foreach (TypeVariable! v in node.TypeParameters) + RemoveBoundVar(BoundTypeVarsDict, v); + } + return res; + } + public override Result Visit(VCExprLet! node, Arg arg) { + // we temporarily add bound term variables to the + // corresponding lists + foreach (VCExprVar! v in node.BoundVars) + AddBoundVar(BoundTermVarsDict, v); + + Result res; + try { + res = VisitAfterBinding(node, arg); + } finally { + foreach (VCExprVar! v in node.BoundVars) + RemoveBoundVar(BoundTermVarsDict, v); + } + return res; + } + + //////////////////////////////////////////////////////////////////////////// + // The possibility is provided to look at a (quantifier or let) node + // after its bound variables have been registered + // (when overriding the normal visit-methods, the node will be visited + // before the binding happens) + + protected virtual Result VisitAfterBinding(VCExprQuantifier! node, Arg arg) { + return base.Visit(node, arg); + } + + protected virtual Result VisitAfterBinding(VCExprLet! node, Arg arg) { + return base.Visit(node, arg); + } + } + + //////////////////////////////////////////////////////////////////////////// + // General visitor for recursively collecting information in a VCExpr. + // As the visitor is not used anywhere for the time being, it maybe should + // be removed + + public abstract class CollectingVCExprVisitor + : IVCExprVisitor { + protected abstract Result CombineResults(List! results, Arg arg); + + public Result Collect(VCExpr! node, Arg arg) { + return node.Accept(this, arg); + } + + public virtual Result Visit(VCExprLiteral! node, Arg arg) { + return CombineResults(new List (), arg); + } + public virtual Result Visit(VCExprNAry! node, Arg arg) { + List! results = new List (); + foreach (VCExpr! subnode in node) + results.Add(subnode.Accept(this, arg)); + return CombineResults(results, arg); + } + public virtual Result Visit(VCExprVar! node, Arg arg) { + return CombineResults(new List (), arg); + } + public virtual Result Visit(VCExprQuantifier! node, Arg arg) { + List! result = new List (); + result.Add(node.Body.Accept(this, arg)); + foreach (VCTrigger! trigger in node.Triggers) + foreach (VCExpr! expr in trigger.Exprs) + result.Add(expr.Accept(this, arg)); + return CombineResults(result, arg); + } + public virtual Result Visit(VCExprLet! node, Arg arg) { + List! results = new List (); + // visit the bound expressions first + foreach (VCExprLetBinding! binding in node) + results.Add(binding.E.Accept(this, arg)); + results.Add(node.Body.Accept(this, arg)); + return CombineResults(results, arg); + } + } + + //////////////////////////////////////////////////////////////////////////// + + public class SizeComputingVisitor : TraversingVCExprVisitor { + + private int Size = 0; + + public static int ComputeSize(VCExpr! expr) { + SizeComputingVisitor! visitor = new SizeComputingVisitor(); + visitor.Traverse(expr, true); + return visitor.Size; + } + + protected override bool StandardResult(VCExpr! node, bool arg) { + Size = Size + 1; + return true; + } + } + + //////////////////////////////////////////////////////////////////////////// + + // Collect all free term and type variables in a VCExpr. Type variables + // can occur free either in the types of bound variables, or in the type + // parameters of VCExprNAry. + + // the result and argument (of type bool) are not used currently + public class FreeVariableCollector : BoundVarTraversingVCExprVisitor { + public readonly Dictionary! FreeTermVars = new Dictionary (); + public readonly List! FreeTypeVars = new List (); + + // not used + protected override bool StandardResult(VCExpr! node, bool arg) { + return true; + } + + public static Dictionary! FreeTermVariables(VCExpr! node) { + FreeVariableCollector collector = new FreeVariableCollector (); + collector.Traverse(node, true); + return collector.FreeTermVars; + } + + public static List! FreeTypeVariables(VCExpr! node) { + FreeVariableCollector collector = new FreeVariableCollector (); + collector.Traverse(node, true); + return collector.FreeTypeVars; + } + + public void Reset() { + FreeTermVars.Clear(); + FreeTypeVars.Clear(); + } + + public void Collect(VCExpr! node) { + Traverse(node, true); + } + + public void Collect(Type! type) { + AddTypeVariables(type.FreeVariables.ToList()); + } + + ///////////////////////////////////////////////////////////////////////// + + private void CollectTypeVariables(IEnumerable! boundVars) { + foreach (VCExprVar! var in boundVars) + Collect(var.Type); + } + + private void AddTypeVariables(IEnumerable! typeVars) { + foreach (TypeVariable! tvar in typeVars) + if (!BoundTypeVars.Contains(tvar) && !FreeTypeVars.Contains(tvar)) + FreeTypeVars.Add(tvar); + } + + public override bool Visit(VCExprVar! node, bool arg) { + if (!BoundTermVars.Contains(node) && !FreeTermVars.ContainsKey(node)) { + FreeTermVars.Add(node, null); + Collect(node.Type); + } + return true; + } + + public override bool Visit(VCExprNAry! node, bool arg) { + foreach (Type! t in node.TypeArguments) + Collect(t); + return base.Visit(node, arg); + } + + protected override bool VisitAfterBinding(VCExprQuantifier! node, bool arg) { + CollectTypeVariables(node.BoundVars); + return base.VisitAfterBinding(node, arg); + } + + protected override bool VisitAfterBinding(VCExprLet! node, bool arg) { + CollectTypeVariables(node.BoundVars); + return base.VisitAfterBinding(node, arg); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Framework for mutating VCExprs + + // The Visit implementations in the following visitor work + // recursively, apart from the implementation for VCExprNAry that + // uses its own stack when applied to nested nodes with the same + // operator, e.g., (AND (AND (AND ...) ...) ...). This is necessary + // to avoid stack overflows (like in TraversingVCExprVisitor) + + public abstract class MutatingVCExprVisitor + : IVCExprVisitor { + protected readonly VCExpressionGenerator! Gen; + + public MutatingVCExprVisitor(VCExpressionGenerator! gen) { + this.Gen = gen; + } + + public VCExpr! Mutate(VCExpr! expr, Arg arg) { + return expr.Accept(this, arg); + } + + public List! MutateSeq(IEnumerable! exprs, Arg arg) { + List! res = new List (); + foreach (VCExpr! expr in exprs) + res.Add(expr.Accept(this, arg)); + return res; + } + + private List! MutateList(List! exprs, Arg arg) { + bool changed = false; + List! res = new List (); + foreach (VCExpr! expr in exprs) { + VCExpr! newExpr = expr.Accept(this, arg); + if (!Object.ReferenceEquals(expr, newExpr)) + changed = true; + res.Add(newExpr); + } + if (!changed) + return exprs; + return res; + } + + public virtual VCExpr! Visit(VCExprLiteral! node, Arg arg) { + return node; + } + + //////////////////////////////////////////////////////////////////////////// + + // Special element used to mark the positions in the todo-stack where + // results have to be popped from the result-stack. + private static readonly VCExpr! CombineResultsMarker = new VCExprLiteral (Type.Bool); + + // The todo-stack contains records of the shape + // + // arg0 + // arg1 + // arg2 + // ... + // CombineResultsMarker + // f(arg0, arg1, arg2, ...) (the original expression) + + private readonly Stack! NAryExprTodoStack = new Stack (); + private readonly Stack! NAryExprResultStack = new Stack (); + + private void PushTodo(VCExprNAry! exprTodo) { + NAryExprTodoStack.Push(exprTodo); + NAryExprTodoStack.Push(CombineResultsMarker); + for (int i = exprTodo.Arity - 1; i >= 0; --i) + NAryExprTodoStack.Push(exprTodo[i]); + } + + public virtual VCExpr! Visit(VCExprNAry! node, Arg arg) { + VCExprOp! op = node.Op; + int initialStackSize = NAryExprTodoStack.Count; + int initialResultStackSize = NAryExprResultStack.Count; + + PushTodo(node); + + while (NAryExprTodoStack.Count > initialStackSize) { + VCExpr! subExpr = NAryExprTodoStack.Pop(); + + if (Object.ReferenceEquals(subExpr, CombineResultsMarker)) { + // + // assemble a result + VCExprNAry! originalExpr = (VCExprNAry)NAryExprTodoStack.Pop(); + bool changed = false; + List! newSubExprs = new List (); + + for (int i = op.Arity - 1; i >= 0; --i) { + VCExpr! nextSubExpr = NAryExprResultStack.Pop(); + if (!Object.ReferenceEquals(nextSubExpr, originalExpr[i])) + changed = true; + newSubExprs.Insert(0, nextSubExpr); + } + + NAryExprResultStack.Push(UpdateModifiedNode(originalExpr, newSubExprs, changed, arg)); + // + } else { + // + VCExprNAry narySubExpr = subExpr as VCExprNAry; + if (narySubExpr != null && narySubExpr.Op.Equals(op) && + // as in VCExprNAryUniformOpEnumerator, all expressions with + // type parameters are allowed to be inspected more closely + narySubExpr.TypeParamArity == 0) { + PushTodo(narySubExpr); + } else { + NAryExprResultStack.Push(subExpr.Accept(this, arg)); + } + // + } + } + + assert NAryExprTodoStack.Count == initialStackSize && + NAryExprResultStack.Count == initialResultStackSize + 1; + return NAryExprResultStack.Pop(); + } + + protected virtual VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, + List! newSubExprs, + // has any of the subexpressions changed? + bool changed, + Arg arg) { + if (changed) + return Gen.Function(originalNode.Op, + newSubExprs, originalNode.TypeArguments); + else + return originalNode; + } + + //////////////////////////////////////////////////////////////////////////// + + public virtual VCExpr! Visit(VCExprVar! node, Arg arg) { + return node; + } + + protected List! MutateTriggers(List! triggers, Arg arg) { + List! newTriggers = new List (); + bool changed = false; + foreach (VCTrigger! trigger in triggers) { + List! exprs = trigger.Exprs; + List! newExprs = MutateList(exprs, arg); + if (Object.ReferenceEquals(exprs, newExprs)) { + newTriggers.Add(trigger); + } else { + newTriggers.Add(Gen.Trigger(trigger.Pos, newExprs)); + changed = true; + } + } + if (!changed) + return triggers; + return newTriggers; + } + + public virtual VCExpr! Visit(VCExprQuantifier! node, Arg arg) { + bool changed = false; + + VCExpr! body = node.Body; + VCExpr! newbody = body.Accept(this, arg); + if (!Object.ReferenceEquals(body, newbody)) + changed = true; + + // visit the trigger expressions as well + List! triggers = node.Triggers; + List! newTriggers = MutateTriggers(triggers, arg); + if (!Object.ReferenceEquals(triggers, newTriggers)) + changed = true; + + if (!changed) + return node; + return Gen.Quantify(node.Quan, node.TypeParameters, node.BoundVars, + newTriggers, node.Infos, newbody); + } + + public virtual VCExpr! Visit(VCExprLet! node, Arg arg) { + bool changed = false; + + VCExpr! body = node.Body; + VCExpr! newbody = body.Accept(this, arg); + if (!Object.ReferenceEquals(body, newbody)) + changed = true; + + List! newbindings = new List (); + for (int i = 0; i < node.Length; ++i) { + VCExprLetBinding! binding = node[i]; + VCExpr! e = binding.E; + VCExpr! newE = e.Accept(this, arg); + if (Object.ReferenceEquals(e, newE)) { + newbindings.Add(binding); + } else { + changed = true; + newbindings.Add(Gen.LetBinding(binding.V, newE)); + } + } + + if (!changed) + return node; + return Gen.Let(newbindings, newbody); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Substitutions and a visitor for applying substitutions. A substitution can + // substitute both type variables and term variables + + public class VCExprSubstitution { + private readonly List!>! TermSubsts; + private readonly List!>! TypeSubsts; + + public VCExprSubstitution(IDictionary! termSubst, + IDictionary! typeSubst) { + List!>! termSubsts = + new List!> (); + termSubsts.Add(termSubst); + List!>! typeSubsts = + new List!> (); + typeSubsts.Add(typeSubst); + this.TermSubsts = termSubsts; + this.TypeSubsts = typeSubsts; + } + + public VCExprSubstitution() { + this(new Dictionary (), new Dictionary ()); + } + + public void PushScope() { + TermSubsts.Add(new Dictionary ()); + TypeSubsts.Add(new Dictionary ()); + } + + public void PopScope() { + TermSubsts.RemoveAt(TermSubsts.Count - 1); + TypeSubsts.RemoveAt(TypeSubsts.Count - 1); + } + + public VCExpr this[VCExprVar! var] { + get { + VCExpr res; + for (int i = TermSubsts.Count - 1; i >= 0; --i) { + if (TermSubsts[i].TryGetValue(var, out res)) + return res; + } + return null; + } + set { + TermSubsts[TermSubsts.Count - 1][var] = (!)value; + } + } + + public Type this[TypeVariable! var] { + get { + Type res; + for (int i = TypeSubsts.Count - 1; i >= 0; --i) { + if (TypeSubsts[i].TryGetValue(var, out res)) + return res; + } + return null; + } + set { + TypeSubsts[TypeSubsts.Count - 1][var] = (!)value; + } + } + + public bool ContainsKey(VCExprVar! var) { + return this[var] != null; + } + + public bool ContainsKey(TypeVariable! var) { + return this[var] != null; + } + + public bool TermSubstIsEmpty { get { + return forall{IDictionary! dict in TermSubsts; + dict.Count == 0}; + } } + + public bool TypeSubstIsEmpty { get { + return forall{IDictionary! dict in TypeSubsts; + dict.Count == 0}; + } } + + public IDictionary! ToTypeSubst { get { + IDictionary! res = new Dictionary (); + foreach (IDictionary! dict in TypeSubsts) + foreach (KeyValuePair pair in dict) + // later ones overwrite earlier ones + res[pair.Key] = pair.Value; + return res; + } } + + // the variables that are not mapped to themselves + public IEnumerable! TermDomain { get { + Dictionary! domain = new Dictionary (); + foreach (IDictionary! dict in TermSubsts) + foreach (VCExprVar! var in dict.Keys) + if (!var.Equals(this[var])) + domain.Add(var, true); + return domain.Keys; + } } + + // the variables that are not mapped to themselves + public IEnumerable! TypeDomain { get { + Dictionary! domain = new Dictionary (); + foreach (IDictionary! dict in TypeSubsts) + foreach (TypeVariable! var in dict.Keys) + if (!var.Equals(this[var])) + domain.Add(var, true); + return domain.Keys; + } } + + public FreeVariableCollector! Codomains { get { + FreeVariableCollector! coll = new FreeVariableCollector (); + foreach (VCExprVar! var in TermDomain) + coll.Collect((!)this[var]); + foreach (TypeVariable! var in TypeDomain) + coll.Collect((!)this[var]); + return coll; + } } + + public VCExprSubstitution! Clone() { + VCExprSubstitution! res = new VCExprSubstitution (); + foreach (IDictionary! dict in TermSubsts) + res.TermSubsts.Add(HelperFuns.Clone(dict)); + foreach (IDictionary! dict in TypeSubsts) + res.TypeSubsts.Add(HelperFuns.Clone(dict)); + return res; + } + } + + ///////////////////////////////////////////////////////////////////////////////// + + public class SubstitutingVCExprVisitor + : MutatingVCExprVisitor { + public SubstitutingVCExprVisitor(VCExpressionGenerator! gen) { + base(gen); + } + + // when descending across a binder, we have to check that no collisions + // or variable capture can occur. if this might happen, we replace the + // term and type variables bound by the binder with fresh variables + private bool CollisionPossible(IEnumerable! typeParams, + IEnumerable! boundVars, + VCExprSubstitution! substitution) { + // variables can be shadowed by a binder + if (exists{TypeVariable! var in typeParams; substitution.ContainsKey(var)} || + exists{VCExprVar! var in boundVars; substitution.ContainsKey(var)}) + return true; + // compute the codomain of the substitution + FreeVariableCollector! coll = substitution.Codomains; + // variables could be captured when applying the substitution + return exists{TypeVariable! var in typeParams; coll.FreeTypeVars.Contains(var)} || + exists{VCExprVar! var in boundVars; coll.FreeTermVars.ContainsKey(var)}; + } + + // can be overwritten if names of bound variables are to be changed + protected virtual string! ChooseNewVariableName(string! oldName) { + return oldName; + } + + // handle type parameters in VCExprNAry + protected override VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, + List! newSubExprs, + bool changed, + VCExprSubstitution! substitution) { + List! typeParams = new List (); + foreach (Type! t in originalNode.TypeArguments) { + Type! newType = t.Substitute(substitution.ToTypeSubst); + if (!ReferenceEquals(t, newType)) + changed = true; + typeParams.Add(newType); + } + if (changed) + return Gen.Function(originalNode.Op, newSubExprs, typeParams); + else + return originalNode; + } + + public override VCExpr! Visit(VCExprQuantifier! node, + VCExprSubstitution! substitution) { + // the default is to refresh bound variables only if necessary + // because of collisions + return Visit(node, substitution, false); + } + + public VCExpr! Visit(VCExprQuantifier! node, + VCExprSubstitution! substitution, + bool refreshBoundVariables) { + substitution.PushScope(); try { + + List! typeParams = node.TypeParameters; + bool refreshAllVariables = refreshBoundVariables || + CollisionPossible(node.TypeParameters, node.BoundVars, substitution); + if (refreshAllVariables) { + // we introduce fresh type variables to ensure that none gets captured + typeParams = new List (); + foreach (TypeVariable! var in node.TypeParameters) { + TypeVariable! freshVar = + new TypeVariable (Token.NoToken, ChooseNewVariableName(var.Name)); + typeParams.Add(freshVar); + substitution[var] = freshVar; + // this might overwrite other elements of the substitution, deliberately + } + } + + List! boundVars = node.BoundVars; + if (refreshAllVariables || !substitution.TypeSubstIsEmpty) { + // collisions are possible, or we also substitute type variables. in this case + // the bound term variables have to be replaced with fresh variables with the + // right types + boundVars = new List (); + IDictionary! typeSubst = substitution.ToTypeSubst; + foreach (VCExprVar! var in node.BoundVars) { + VCExprVar! freshVar = + Gen.Variable(ChooseNewVariableName(var.Name), + var.Type.Substitute(typeSubst)); + boundVars.Add(freshVar); + substitution[var] = freshVar; + // this might overwrite other elements of the substitution, deliberately + } + } + + List! newTriggers = new List (); + foreach (VCTrigger! trigger in node.Triggers) + newTriggers.Add(Gen.Trigger(trigger.Pos, MutateSeq(trigger.Exprs, substitution))); + + VCExpr! newBody = Mutate(node.Body, substitution); + + return Gen.Quantify(node.Quan, typeParams, boundVars, + newTriggers, node.Infos, newBody); + + } finally { + substitution.PopScope(); + } + } + + public override VCExpr! Visit(VCExprVar! node, + VCExprSubstitution! substitution) { + VCExpr res = substitution[node]; + if (res != null) + return res; + return node; + } + + public override VCExpr! Visit(VCExprLet! node, + VCExprSubstitution! substitution) { + // the default is to refresh bound variables only if necessary + // because of collisions + return Visit(node, substitution, false); + } + + public VCExpr! Visit(VCExprLet! node, + VCExprSubstitution! substitution, + bool refreshBoundVariables) { + // let-expressions do not have type parameters (fortunately ...) + substitution.PushScope (); try { + + bool refreshAllVariables = + refreshBoundVariables || + !substitution.TypeSubstIsEmpty || + CollisionPossible(new List (), node.BoundVars, substitution); + + List! newBoundVars = node.BoundVars; + if (refreshAllVariables) { + // collisions are possible, or we also substitute type variables. in this case + // the bound term variables have to be replaced with fresh variables with the + // right types + newBoundVars = new List (); + IDictionary! typeSubst = substitution.ToTypeSubst; + foreach (VCExprVar! var in node.BoundVars) { + VCExprVar! freshVar = + Gen.Variable(ChooseNewVariableName(var.Name), + var.Type.Substitute(typeSubst)); + newBoundVars.Add(freshVar); + substitution[var] = freshVar; + // this might overwrite other elements of the substitution, deliberately + } + } + + List! newbindings = new List (); + for (int i = 0; i < node.Length; ++i) { + VCExprLetBinding! binding = node[i]; + newbindings.Add(Gen.LetBinding(newBoundVars[i], Mutate(binding.E, substitution))); + } + + VCExpr! newBody = Mutate(node.Body, substitution); + return Gen.Let(newbindings, newBody); + + } finally { + substitution.PopScope(); + } + } + } + + //////////////////////////////////////////////////////////////////////////// + + public abstract class StandardVCExprOpVisitor + : IVCExprOpVisitor { + protected abstract Result StandardResult(VCExprNAry! node, Arg arg); + + public virtual Result VisitNotOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitEqOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitNeqOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitAndOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitOrOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitImpliesOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitDistinctOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitLabelOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitSelectOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitStoreOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitBvOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitBvExtractOp(VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitBvConcatOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitIfThenElseOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitCustomOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitAddOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitSubOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitMulOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitDivOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitModOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitLtOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitLeOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitGtOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitGeOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitSubtypeOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitSubtype3Op (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + public virtual Result VisitBoogieFunctionOp (VCExprNAry! node, Arg arg) { + return StandardResult(node, arg); + } + } + +} + + diff --git a/Source/VCExpr/VCExprASTVisitors.ssc b/Source/VCExpr/VCExprASTVisitors.ssc deleted file mode 100644 index c9d56962..00000000 --- a/Source/VCExpr/VCExprASTVisitors.ssc +++ /dev/null @@ -1,1006 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Text; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using Microsoft.Contracts; -using Microsoft.Basetypes; - -// Some visitor skeletons for the VCExpression AST - -namespace Microsoft.Boogie.VCExprAST -{ - using Microsoft.Boogie; - - public interface IVCExprVisitor { - Result Visit(VCExprLiteral! node, Arg arg); - Result Visit(VCExprNAry! node, Arg arg); - Result Visit(VCExprVar! node, Arg arg); - Result Visit(VCExprQuantifier! node, Arg arg); - Result Visit(VCExprLet! node, Arg arg); - } - - public interface IVCExprOpVisitor { - Result VisitNotOp (VCExprNAry! node, Arg arg); - Result VisitEqOp (VCExprNAry! node, Arg arg); - Result VisitNeqOp (VCExprNAry! node, Arg arg); - Result VisitAndOp (VCExprNAry! node, Arg arg); - Result VisitOrOp (VCExprNAry! node, Arg arg); - Result VisitImpliesOp (VCExprNAry! node, Arg arg); - Result VisitDistinctOp (VCExprNAry! node, Arg arg); - Result VisitLabelOp (VCExprNAry! node, Arg arg); - Result VisitSelectOp (VCExprNAry! node, Arg arg); - Result VisitStoreOp (VCExprNAry! node, Arg arg); - Result VisitBvOp (VCExprNAry! node, Arg arg); - Result VisitBvExtractOp(VCExprNAry! node, Arg arg); - Result VisitBvConcatOp (VCExprNAry! node, Arg arg); - Result VisitAddOp (VCExprNAry! node, Arg arg); - Result VisitSubOp (VCExprNAry! node, Arg arg); - Result VisitMulOp (VCExprNAry! node, Arg arg); - Result VisitDivOp (VCExprNAry! node, Arg arg); - Result VisitModOp (VCExprNAry! node, Arg arg); - Result VisitLtOp (VCExprNAry! node, Arg arg); - Result VisitLeOp (VCExprNAry! node, Arg arg); - Result VisitGtOp (VCExprNAry! node, Arg arg); - Result VisitGeOp (VCExprNAry! node, Arg arg); - Result VisitSubtypeOp (VCExprNAry! node, Arg arg); - Result VisitSubtype3Op (VCExprNAry! node, Arg arg); - Result VisitBoogieFunctionOp (VCExprNAry! node, Arg arg); - Result VisitIfThenElseOp (VCExprNAry! node, Arg arg); - Result VisitCustomOp (VCExprNAry! node, Arg arg); - } - - ////////////////////////////////////////////////////////////////////////////// - // Standard implementations that make it easier to create own visitors - - // Simple traversal of VCExprs. The Visit implementations work - // recursively, apart from the implementation for VCExprNAry that - // uses a stack when applied to nested nodes with the same - // operator, e.g., (AND (AND (AND ...) ...) ...). This is necessary - // to avoid stack overflows - - public abstract class TraversingVCExprVisitor - : IVCExprVisitor { - protected abstract Result StandardResult(VCExpr! node, Arg arg); - - public Result Traverse(VCExpr! node, Arg arg) { - return node.Accept(this, arg); - } - - public virtual Result Visit(VCExprLiteral! node, Arg arg) { - return StandardResult(node, arg); - } - - public virtual Result Visit(VCExprNAry! node, Arg arg) { - Result res = StandardResult(node, arg); - - if (node.TypeParamArity == 0) { - VCExprOp! op = node.Op; - - IEnumerator enumerator = new VCExprNAryUniformOpEnumerator(node); - enumerator.MoveNext(); // skip the node itself - - while (enumerator.MoveNext()) { - VCExpr! expr = (VCExpr!)enumerator.Current; - VCExprNAry naryExpr = expr as VCExprNAry; - if (naryExpr == null || !naryExpr.Op.Equals(op)) { - expr.Accept(this, arg); - } else { - StandardResult(expr, arg); - } - } - } else { - foreach (VCExpr! e in node) - e.Accept(this, arg); - } - - return res; - } - - public virtual Result Visit(VCExprVar! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result Visit(VCExprQuantifier! node, Arg arg) { - Result res = StandardResult(node, arg); - foreach (VCTrigger! trigger in node.Triggers) - foreach (VCExpr! expr in trigger.Exprs) - expr.Accept(this, arg); - node.Body.Accept(this, arg); - return res; - } - public virtual Result Visit(VCExprLet! node, Arg arg) { - Result res = StandardResult(node, arg); - // visit the bound expressions first - foreach (VCExprLetBinding! binding in node) - binding.E.Accept(this, arg); - node.Body.Accept(this, arg); - return res; - } - } - - ////////////////////////////////////////////////////////////////////////////// - // Class to iterate over the nodes of a tree of VCExprNAry. This is - // used to avoid handling such VCExpr recursively, which can easily - // lead to stack overflows - - public class VCExprNAryEnumerator : IEnumerator { - - private readonly VCExprNAry! CompleteExpr; - private VCExpr CurrentExpr = null; - private readonly Stack! ExprTodo = new Stack (); - - public VCExprNAryEnumerator(VCExprNAry! completeExpr) { - this.CompleteExpr = completeExpr; - Stack! exprTodo = new Stack (); - exprTodo.Push(completeExpr); - ExprTodo = exprTodo; - } - - // Method using which a subclass can decide whether the - // subexpressions of an expression should be enumerated as well - // The default is to enumerate all nodes - protected virtual bool Descend(VCExprNAry! expr) { - return true; - } - - //////////////////////////////////////////////////////////////////////////// - - public bool MoveNext() { - if (ExprTodo.Count == 0) - return false; - - CurrentExpr = ExprTodo.Pop(); - VCExprNAry currentNAry = CurrentExpr as VCExprNAry; - if (currentNAry != null && Descend(currentNAry)) { - for (int i = currentNAry.Arity - 1; i >= 0; --i) - ExprTodo.Push(currentNAry[i]); - } - - return true; - } - - public object Current { - get { - return (!)CurrentExpr; - } } - - public void Reset() { - ExprTodo.Clear(); - CurrentExpr = null; - ExprTodo.Push(CompleteExpr); - } - } - - - ////////////////////////////////////////////////////////////////////////////// - - public class VCExprNAryUniformOpEnumerator : VCExprNAryEnumerator { - private readonly VCExprOp! Op; - public VCExprNAryUniformOpEnumerator(VCExprNAry! completeExpr) { - base(completeExpr); - this.Op = completeExpr.Op; - } - protected override bool Descend(VCExprNAry! expr) { - return expr.Op.Equals(Op) && - // we never skip nodes with type parameters - // (those are too interesting ...) - expr.TypeParamArity == 0; - } - } - - ////////////////////////////////////////////////////////////////////////////// - // Visitor that knows about the variables bound at each location in a VCExpr - - public abstract class BoundVarTraversingVCExprVisitor - : TraversingVCExprVisitor { - // Maps with all variables bound above a certain location in the VCExpression. - // The value of the map tells how often a particular symbol was bound - private readonly IDictionary! BoundTermVarsDict = - new Dictionary (); - private readonly IDictionary! BoundTypeVarsDict = - new Dictionary (); - - protected ICollection! BoundTermVars { get { - return BoundTermVarsDict.Keys; - } } - protected ICollection! BoundTypeVars { get { - return BoundTypeVarsDict.Keys; - } } - - private void AddBoundVar(IDictionary! dict, T! sym) { - int n; - if (dict.TryGetValue(sym, out n)) - dict[sym] = n + 1; - else - dict[sym] = 1; - } - - private void RemoveBoundVar(IDictionary! dict, T! sym) { - int n; - bool b = dict.TryGetValue(sym, out n); - assert b && n > 0; - if (n == 1) - dict.Remove(sym); - else - dict[sym] = n - 1; - } - - public override Result Visit(VCExprQuantifier! node, Arg arg) { - // we temporarily add bound (term and type) variables to the - // corresponding lists - foreach (VCExprVar! v in node.BoundVars) - AddBoundVar(BoundTermVarsDict, v); - foreach (TypeVariable! v in node.TypeParameters) - AddBoundVar(BoundTypeVarsDict, v); - - Result res; - try { - res = VisitAfterBinding(node, arg); - } finally { - foreach (VCExprVar! v in node.BoundVars) - RemoveBoundVar(BoundTermVarsDict, v); - foreach (TypeVariable! v in node.TypeParameters) - RemoveBoundVar(BoundTypeVarsDict, v); - } - return res; - } - public override Result Visit(VCExprLet! node, Arg arg) { - // we temporarily add bound term variables to the - // corresponding lists - foreach (VCExprVar! v in node.BoundVars) - AddBoundVar(BoundTermVarsDict, v); - - Result res; - try { - res = VisitAfterBinding(node, arg); - } finally { - foreach (VCExprVar! v in node.BoundVars) - RemoveBoundVar(BoundTermVarsDict, v); - } - return res; - } - - //////////////////////////////////////////////////////////////////////////// - // The possibility is provided to look at a (quantifier or let) node - // after its bound variables have been registered - // (when overriding the normal visit-methods, the node will be visited - // before the binding happens) - - protected virtual Result VisitAfterBinding(VCExprQuantifier! node, Arg arg) { - return base.Visit(node, arg); - } - - protected virtual Result VisitAfterBinding(VCExprLet! node, Arg arg) { - return base.Visit(node, arg); - } - } - - //////////////////////////////////////////////////////////////////////////// - // General visitor for recursively collecting information in a VCExpr. - // As the visitor is not used anywhere for the time being, it maybe should - // be removed - - public abstract class CollectingVCExprVisitor - : IVCExprVisitor { - protected abstract Result CombineResults(List! results, Arg arg); - - public Result Collect(VCExpr! node, Arg arg) { - return node.Accept(this, arg); - } - - public virtual Result Visit(VCExprLiteral! node, Arg arg) { - return CombineResults(new List (), arg); - } - public virtual Result Visit(VCExprNAry! node, Arg arg) { - List! results = new List (); - foreach (VCExpr! subnode in node) - results.Add(subnode.Accept(this, arg)); - return CombineResults(results, arg); - } - public virtual Result Visit(VCExprVar! node, Arg arg) { - return CombineResults(new List (), arg); - } - public virtual Result Visit(VCExprQuantifier! node, Arg arg) { - List! result = new List (); - result.Add(node.Body.Accept(this, arg)); - foreach (VCTrigger! trigger in node.Triggers) - foreach (VCExpr! expr in trigger.Exprs) - result.Add(expr.Accept(this, arg)); - return CombineResults(result, arg); - } - public virtual Result Visit(VCExprLet! node, Arg arg) { - List! results = new List (); - // visit the bound expressions first - foreach (VCExprLetBinding! binding in node) - results.Add(binding.E.Accept(this, arg)); - results.Add(node.Body.Accept(this, arg)); - return CombineResults(results, arg); - } - } - - //////////////////////////////////////////////////////////////////////////// - - public class SizeComputingVisitor : TraversingVCExprVisitor { - - private int Size = 0; - - public static int ComputeSize(VCExpr! expr) { - SizeComputingVisitor! visitor = new SizeComputingVisitor(); - visitor.Traverse(expr, true); - return visitor.Size; - } - - protected override bool StandardResult(VCExpr! node, bool arg) { - Size = Size + 1; - return true; - } - } - - //////////////////////////////////////////////////////////////////////////// - - // Collect all free term and type variables in a VCExpr. Type variables - // can occur free either in the types of bound variables, or in the type - // parameters of VCExprNAry. - - // the result and argument (of type bool) are not used currently - public class FreeVariableCollector : BoundVarTraversingVCExprVisitor { - public readonly Dictionary! FreeTermVars = new Dictionary (); - public readonly List! FreeTypeVars = new List (); - - // not used - protected override bool StandardResult(VCExpr! node, bool arg) { - return true; - } - - public static Dictionary! FreeTermVariables(VCExpr! node) { - FreeVariableCollector collector = new FreeVariableCollector (); - collector.Traverse(node, true); - return collector.FreeTermVars; - } - - public static List! FreeTypeVariables(VCExpr! node) { - FreeVariableCollector collector = new FreeVariableCollector (); - collector.Traverse(node, true); - return collector.FreeTypeVars; - } - - public void Reset() { - FreeTermVars.Clear(); - FreeTypeVars.Clear(); - } - - public void Collect(VCExpr! node) { - Traverse(node, true); - } - - public void Collect(Type! type) { - AddTypeVariables(type.FreeVariables.ToList()); - } - - ///////////////////////////////////////////////////////////////////////// - - private void CollectTypeVariables(IEnumerable! boundVars) { - foreach (VCExprVar! var in boundVars) - Collect(var.Type); - } - - private void AddTypeVariables(IEnumerable! typeVars) { - foreach (TypeVariable! tvar in typeVars) - if (!BoundTypeVars.Contains(tvar) && !FreeTypeVars.Contains(tvar)) - FreeTypeVars.Add(tvar); - } - - public override bool Visit(VCExprVar! node, bool arg) { - if (!BoundTermVars.Contains(node) && !FreeTermVars.ContainsKey(node)) { - FreeTermVars.Add(node, null); - Collect(node.Type); - } - return true; - } - - public override bool Visit(VCExprNAry! node, bool arg) { - foreach (Type! t in node.TypeArguments) - Collect(t); - return base.Visit(node, arg); - } - - protected override bool VisitAfterBinding(VCExprQuantifier! node, bool arg) { - CollectTypeVariables(node.BoundVars); - return base.VisitAfterBinding(node, arg); - } - - protected override bool VisitAfterBinding(VCExprLet! node, bool arg) { - CollectTypeVariables(node.BoundVars); - return base.VisitAfterBinding(node, arg); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Framework for mutating VCExprs - - // The Visit implementations in the following visitor work - // recursively, apart from the implementation for VCExprNAry that - // uses its own stack when applied to nested nodes with the same - // operator, e.g., (AND (AND (AND ...) ...) ...). This is necessary - // to avoid stack overflows (like in TraversingVCExprVisitor) - - public abstract class MutatingVCExprVisitor - : IVCExprVisitor { - protected readonly VCExpressionGenerator! Gen; - - public MutatingVCExprVisitor(VCExpressionGenerator! gen) { - this.Gen = gen; - } - - public VCExpr! Mutate(VCExpr! expr, Arg arg) { - return expr.Accept(this, arg); - } - - public List! MutateSeq(IEnumerable! exprs, Arg arg) { - List! res = new List (); - foreach (VCExpr! expr in exprs) - res.Add(expr.Accept(this, arg)); - return res; - } - - private List! MutateList(List! exprs, Arg arg) { - bool changed = false; - List! res = new List (); - foreach (VCExpr! expr in exprs) { - VCExpr! newExpr = expr.Accept(this, arg); - if (!Object.ReferenceEquals(expr, newExpr)) - changed = true; - res.Add(newExpr); - } - if (!changed) - return exprs; - return res; - } - - public virtual VCExpr! Visit(VCExprLiteral! node, Arg arg) { - return node; - } - - //////////////////////////////////////////////////////////////////////////// - - // Special element used to mark the positions in the todo-stack where - // results have to be popped from the result-stack. - private static readonly VCExpr! CombineResultsMarker = new VCExprLiteral (Type.Bool); - - // The todo-stack contains records of the shape - // - // arg0 - // arg1 - // arg2 - // ... - // CombineResultsMarker - // f(arg0, arg1, arg2, ...) (the original expression) - - private readonly Stack! NAryExprTodoStack = new Stack (); - private readonly Stack! NAryExprResultStack = new Stack (); - - private void PushTodo(VCExprNAry! exprTodo) { - NAryExprTodoStack.Push(exprTodo); - NAryExprTodoStack.Push(CombineResultsMarker); - for (int i = exprTodo.Arity - 1; i >= 0; --i) - NAryExprTodoStack.Push(exprTodo[i]); - } - - public virtual VCExpr! Visit(VCExprNAry! node, Arg arg) { - VCExprOp! op = node.Op; - int initialStackSize = NAryExprTodoStack.Count; - int initialResultStackSize = NAryExprResultStack.Count; - - PushTodo(node); - - while (NAryExprTodoStack.Count > initialStackSize) { - VCExpr! subExpr = NAryExprTodoStack.Pop(); - - if (Object.ReferenceEquals(subExpr, CombineResultsMarker)) { - // - // assemble a result - VCExprNAry! originalExpr = (VCExprNAry)NAryExprTodoStack.Pop(); - bool changed = false; - List! newSubExprs = new List (); - - for (int i = op.Arity - 1; i >= 0; --i) { - VCExpr! nextSubExpr = NAryExprResultStack.Pop(); - if (!Object.ReferenceEquals(nextSubExpr, originalExpr[i])) - changed = true; - newSubExprs.Insert(0, nextSubExpr); - } - - NAryExprResultStack.Push(UpdateModifiedNode(originalExpr, newSubExprs, changed, arg)); - // - } else { - // - VCExprNAry narySubExpr = subExpr as VCExprNAry; - if (narySubExpr != null && narySubExpr.Op.Equals(op) && - // as in VCExprNAryUniformOpEnumerator, all expressions with - // type parameters are allowed to be inspected more closely - narySubExpr.TypeParamArity == 0) { - PushTodo(narySubExpr); - } else { - NAryExprResultStack.Push(subExpr.Accept(this, arg)); - } - // - } - } - - assert NAryExprTodoStack.Count == initialStackSize && - NAryExprResultStack.Count == initialResultStackSize + 1; - return NAryExprResultStack.Pop(); - } - - protected virtual VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, - List! newSubExprs, - // has any of the subexpressions changed? - bool changed, - Arg arg) { - if (changed) - return Gen.Function(originalNode.Op, - newSubExprs, originalNode.TypeArguments); - else - return originalNode; - } - - //////////////////////////////////////////////////////////////////////////// - - public virtual VCExpr! Visit(VCExprVar! node, Arg arg) { - return node; - } - - protected List! MutateTriggers(List! triggers, Arg arg) { - List! newTriggers = new List (); - bool changed = false; - foreach (VCTrigger! trigger in triggers) { - List! exprs = trigger.Exprs; - List! newExprs = MutateList(exprs, arg); - if (Object.ReferenceEquals(exprs, newExprs)) { - newTriggers.Add(trigger); - } else { - newTriggers.Add(Gen.Trigger(trigger.Pos, newExprs)); - changed = true; - } - } - if (!changed) - return triggers; - return newTriggers; - } - - public virtual VCExpr! Visit(VCExprQuantifier! node, Arg arg) { - bool changed = false; - - VCExpr! body = node.Body; - VCExpr! newbody = body.Accept(this, arg); - if (!Object.ReferenceEquals(body, newbody)) - changed = true; - - // visit the trigger expressions as well - List! triggers = node.Triggers; - List! newTriggers = MutateTriggers(triggers, arg); - if (!Object.ReferenceEquals(triggers, newTriggers)) - changed = true; - - if (!changed) - return node; - return Gen.Quantify(node.Quan, node.TypeParameters, node.BoundVars, - newTriggers, node.Infos, newbody); - } - - public virtual VCExpr! Visit(VCExprLet! node, Arg arg) { - bool changed = false; - - VCExpr! body = node.Body; - VCExpr! newbody = body.Accept(this, arg); - if (!Object.ReferenceEquals(body, newbody)) - changed = true; - - List! newbindings = new List (); - for (int i = 0; i < node.Length; ++i) { - VCExprLetBinding! binding = node[i]; - VCExpr! e = binding.E; - VCExpr! newE = e.Accept(this, arg); - if (Object.ReferenceEquals(e, newE)) { - newbindings.Add(binding); - } else { - changed = true; - newbindings.Add(Gen.LetBinding(binding.V, newE)); - } - } - - if (!changed) - return node; - return Gen.Let(newbindings, newbody); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Substitutions and a visitor for applying substitutions. A substitution can - // substitute both type variables and term variables - - public class VCExprSubstitution { - private readonly List!>! TermSubsts; - private readonly List!>! TypeSubsts; - - public VCExprSubstitution(IDictionary! termSubst, - IDictionary! typeSubst) { - List!>! termSubsts = - new List!> (); - termSubsts.Add(termSubst); - List!>! typeSubsts = - new List!> (); - typeSubsts.Add(typeSubst); - this.TermSubsts = termSubsts; - this.TypeSubsts = typeSubsts; - } - - public VCExprSubstitution() { - this(new Dictionary (), new Dictionary ()); - } - - public void PushScope() { - TermSubsts.Add(new Dictionary ()); - TypeSubsts.Add(new Dictionary ()); - } - - public void PopScope() { - TermSubsts.RemoveAt(TermSubsts.Count - 1); - TypeSubsts.RemoveAt(TypeSubsts.Count - 1); - } - - public VCExpr this[VCExprVar! var] { - get { - VCExpr res; - for (int i = TermSubsts.Count - 1; i >= 0; --i) { - if (TermSubsts[i].TryGetValue(var, out res)) - return res; - } - return null; - } - set { - TermSubsts[TermSubsts.Count - 1][var] = (!)value; - } - } - - public Type this[TypeVariable! var] { - get { - Type res; - for (int i = TypeSubsts.Count - 1; i >= 0; --i) { - if (TypeSubsts[i].TryGetValue(var, out res)) - return res; - } - return null; - } - set { - TypeSubsts[TypeSubsts.Count - 1][var] = (!)value; - } - } - - public bool ContainsKey(VCExprVar! var) { - return this[var] != null; - } - - public bool ContainsKey(TypeVariable! var) { - return this[var] != null; - } - - public bool TermSubstIsEmpty { get { - return forall{IDictionary! dict in TermSubsts; - dict.Count == 0}; - } } - - public bool TypeSubstIsEmpty { get { - return forall{IDictionary! dict in TypeSubsts; - dict.Count == 0}; - } } - - public IDictionary! ToTypeSubst { get { - IDictionary! res = new Dictionary (); - foreach (IDictionary! dict in TypeSubsts) - foreach (KeyValuePair pair in dict) - // later ones overwrite earlier ones - res[pair.Key] = pair.Value; - return res; - } } - - // the variables that are not mapped to themselves - public IEnumerable! TermDomain { get { - Dictionary! domain = new Dictionary (); - foreach (IDictionary! dict in TermSubsts) - foreach (VCExprVar! var in dict.Keys) - if (!var.Equals(this[var])) - domain.Add(var, true); - return domain.Keys; - } } - - // the variables that are not mapped to themselves - public IEnumerable! TypeDomain { get { - Dictionary! domain = new Dictionary (); - foreach (IDictionary! dict in TypeSubsts) - foreach (TypeVariable! var in dict.Keys) - if (!var.Equals(this[var])) - domain.Add(var, true); - return domain.Keys; - } } - - public FreeVariableCollector! Codomains { get { - FreeVariableCollector! coll = new FreeVariableCollector (); - foreach (VCExprVar! var in TermDomain) - coll.Collect((!)this[var]); - foreach (TypeVariable! var in TypeDomain) - coll.Collect((!)this[var]); - return coll; - } } - - public VCExprSubstitution! Clone() { - VCExprSubstitution! res = new VCExprSubstitution (); - foreach (IDictionary! dict in TermSubsts) - res.TermSubsts.Add(HelperFuns.Clone(dict)); - foreach (IDictionary! dict in TypeSubsts) - res.TypeSubsts.Add(HelperFuns.Clone(dict)); - return res; - } - } - - ///////////////////////////////////////////////////////////////////////////////// - - public class SubstitutingVCExprVisitor - : MutatingVCExprVisitor { - public SubstitutingVCExprVisitor(VCExpressionGenerator! gen) { - base(gen); - } - - // when descending across a binder, we have to check that no collisions - // or variable capture can occur. if this might happen, we replace the - // term and type variables bound by the binder with fresh variables - private bool CollisionPossible(IEnumerable! typeParams, - IEnumerable! boundVars, - VCExprSubstitution! substitution) { - // variables can be shadowed by a binder - if (exists{TypeVariable! var in typeParams; substitution.ContainsKey(var)} || - exists{VCExprVar! var in boundVars; substitution.ContainsKey(var)}) - return true; - // compute the codomain of the substitution - FreeVariableCollector! coll = substitution.Codomains; - // variables could be captured when applying the substitution - return exists{TypeVariable! var in typeParams; coll.FreeTypeVars.Contains(var)} || - exists{VCExprVar! var in boundVars; coll.FreeTermVars.ContainsKey(var)}; - } - - // can be overwritten if names of bound variables are to be changed - protected virtual string! ChooseNewVariableName(string! oldName) { - return oldName; - } - - // handle type parameters in VCExprNAry - protected override VCExpr! UpdateModifiedNode(VCExprNAry! originalNode, - List! newSubExprs, - bool changed, - VCExprSubstitution! substitution) { - List! typeParams = new List (); - foreach (Type! t in originalNode.TypeArguments) { - Type! newType = t.Substitute(substitution.ToTypeSubst); - if (!ReferenceEquals(t, newType)) - changed = true; - typeParams.Add(newType); - } - if (changed) - return Gen.Function(originalNode.Op, newSubExprs, typeParams); - else - return originalNode; - } - - public override VCExpr! Visit(VCExprQuantifier! node, - VCExprSubstitution! substitution) { - // the default is to refresh bound variables only if necessary - // because of collisions - return Visit(node, substitution, false); - } - - public VCExpr! Visit(VCExprQuantifier! node, - VCExprSubstitution! substitution, - bool refreshBoundVariables) { - substitution.PushScope(); try { - - List! typeParams = node.TypeParameters; - bool refreshAllVariables = refreshBoundVariables || - CollisionPossible(node.TypeParameters, node.BoundVars, substitution); - if (refreshAllVariables) { - // we introduce fresh type variables to ensure that none gets captured - typeParams = new List (); - foreach (TypeVariable! var in node.TypeParameters) { - TypeVariable! freshVar = - new TypeVariable (Token.NoToken, ChooseNewVariableName(var.Name)); - typeParams.Add(freshVar); - substitution[var] = freshVar; - // this might overwrite other elements of the substitution, deliberately - } - } - - List! boundVars = node.BoundVars; - if (refreshAllVariables || !substitution.TypeSubstIsEmpty) { - // collisions are possible, or we also substitute type variables. in this case - // the bound term variables have to be replaced with fresh variables with the - // right types - boundVars = new List (); - IDictionary! typeSubst = substitution.ToTypeSubst; - foreach (VCExprVar! var in node.BoundVars) { - VCExprVar! freshVar = - Gen.Variable(ChooseNewVariableName(var.Name), - var.Type.Substitute(typeSubst)); - boundVars.Add(freshVar); - substitution[var] = freshVar; - // this might overwrite other elements of the substitution, deliberately - } - } - - List! newTriggers = new List (); - foreach (VCTrigger! trigger in node.Triggers) - newTriggers.Add(Gen.Trigger(trigger.Pos, MutateSeq(trigger.Exprs, substitution))); - - VCExpr! newBody = Mutate(node.Body, substitution); - - return Gen.Quantify(node.Quan, typeParams, boundVars, - newTriggers, node.Infos, newBody); - - } finally { - substitution.PopScope(); - } - } - - public override VCExpr! Visit(VCExprVar! node, - VCExprSubstitution! substitution) { - VCExpr res = substitution[node]; - if (res != null) - return res; - return node; - } - - public override VCExpr! Visit(VCExprLet! node, - VCExprSubstitution! substitution) { - // the default is to refresh bound variables only if necessary - // because of collisions - return Visit(node, substitution, false); - } - - public VCExpr! Visit(VCExprLet! node, - VCExprSubstitution! substitution, - bool refreshBoundVariables) { - // let-expressions do not have type parameters (fortunately ...) - substitution.PushScope (); try { - - bool refreshAllVariables = - refreshBoundVariables || - !substitution.TypeSubstIsEmpty || - CollisionPossible(new List (), node.BoundVars, substitution); - - List! newBoundVars = node.BoundVars; - if (refreshAllVariables) { - // collisions are possible, or we also substitute type variables. in this case - // the bound term variables have to be replaced with fresh variables with the - // right types - newBoundVars = new List (); - IDictionary! typeSubst = substitution.ToTypeSubst; - foreach (VCExprVar! var in node.BoundVars) { - VCExprVar! freshVar = - Gen.Variable(ChooseNewVariableName(var.Name), - var.Type.Substitute(typeSubst)); - newBoundVars.Add(freshVar); - substitution[var] = freshVar; - // this might overwrite other elements of the substitution, deliberately - } - } - - List! newbindings = new List (); - for (int i = 0; i < node.Length; ++i) { - VCExprLetBinding! binding = node[i]; - newbindings.Add(Gen.LetBinding(newBoundVars[i], Mutate(binding.E, substitution))); - } - - VCExpr! newBody = Mutate(node.Body, substitution); - return Gen.Let(newbindings, newBody); - - } finally { - substitution.PopScope(); - } - } - } - - //////////////////////////////////////////////////////////////////////////// - - public abstract class StandardVCExprOpVisitor - : IVCExprOpVisitor { - protected abstract Result StandardResult(VCExprNAry! node, Arg arg); - - public virtual Result VisitNotOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitEqOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitNeqOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitAndOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitOrOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitImpliesOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitDistinctOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitLabelOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitSelectOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitStoreOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitBvOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitBvExtractOp(VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitBvConcatOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitIfThenElseOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitCustomOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitAddOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitSubOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitMulOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitDivOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitModOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitLtOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitLeOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitGtOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitGeOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitSubtypeOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitSubtype3Op (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - public virtual Result VisitBoogieFunctionOp (VCExprNAry! node, Arg arg) { - return StandardResult(node, arg); - } - } - -} - - -- cgit v1.2.3