//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
using System;
using System.Text;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.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) {
Contract.Requires(gen != null);
Typed2UntypedFunctions = new Dictionary ();
}
// constructor to allow cloning
[NotDelayed]
internal TypeAxiomBuilderArguments(TypeAxiomBuilderArguments builder)
: base(builder) {
Contract.Requires(builder != null);
Typed2UntypedFunctions =
new Dictionary (builder.Typed2UntypedFunctions);
MapTypeAbstracterAttr =
builder.MapTypeAbstracterAttr == null ?
null : new MapTypeAbstractionBuilderArguments(this, builder.Gen,
builder.MapTypeAbstracterAttr);
}
public override Object Clone() {
Contract.Ensures(Contract.Result() != null);
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) {
//Contract.Requires(castFromU != null);
//Contract.Requires(castToU != null);
Contract.Ensures(Contract.Result() != null);
List /*!*/ triggers;
VCExprVar/*!*/ var;
VCExpr/*!*/ eq = GenReverseCastEq(castToU, castFromU, out var, out triggers);
return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, -1, eq);
}
protected override VCExpr GenCastTypeAxioms(Function castToU, Function castFromU) {
//Contract.Requires(castFromU != null);
//Contract.Requires(castToU != null);
Contract.Ensures(Contract.Result() != null);
// nothing
return VCExpressionGenerator.True;
}
private MapTypeAbstractionBuilderArguments MapTypeAbstracterAttr = null;
internal override MapTypeAbstractionBuilder/*!*/ MapTypeAbstracter {
get {
Contract.Ensures(Contract.Result() != null);
if (MapTypeAbstracterAttr == null)
MapTypeAbstracterAttr = new MapTypeAbstractionBuilderArguments(this, Gen);
return MapTypeAbstracterAttr;
}
}
protected override void AddVarTypeAxiom(VCExprVar var, Type originalType) {
//Contract.Requires(originalType != null);
//Contract.Requires(var != null);
// no axioms are needed for variable or function types
}
////////////////////////////////////////////////////////////////////////////
// Symbols for representing functions
// Globally defined functions
private readonly IDictionary /*!*/ Typed2UntypedFunctions;
[ContractInvariantMethod]
void Typed2UntypedFunctionsInvariantMethod() {
Contract.Invariant(cce.NonNullDictionaryAndValues(Typed2UntypedFunctions));
}
public Function Typed2Untyped(Function fun) {
Contract.Requires(fun != null);
Contract.Ensures(Contract.Result() != null);
Function res;
if (!Typed2UntypedFunctions.TryGetValue(fun, out res)) {
Contract.Assert(fun.OutParams.Count == 1);
// if all of the parameters are int or bool, the function does
// not have to be changed
if (fun.InParams.All(param => UnchangedType(cce.NonNull(param).TypedIdent.Type)) &&
UnchangedType(cce.NonNull(fun.OutParams[0]).TypedIdent.Type)) {
res = fun;
} else {
Type[]/*!*/ types = new Type[fun.TypeParameters.Count + fun.InParams.Count + 1];
int i = 0;
// the first arguments are the explicit type parameters
for (int j = 0; j < fun.TypeParameters.Count; ++j) {
types[i] = T;
i = i + 1;
}
// followed by the actual parameters
foreach (Variable/*!*/ x in fun.InParams) {
Contract.Assert(x != null);
types[i] = TypeAfterErasure(x.TypedIdent.Type);
i = i + 1;
}
types[types.Length - 1] = TypeAfterErasure(cce.NonNull(fun.OutParams[0]).TypedIdent.Type);
res = HelperFuns.BoogieFunction(fun.Name, types);
res.Attributes = fun.Attributes;
}
Typed2UntypedFunctions.Add(fun, res);
}
return cce.NonNull(res);
}
}
//////////////////////////////////////////////////////////////////////////////
internal class MapTypeAbstractionBuilderArguments : MapTypeAbstractionBuilder {
private readonly TypeAxiomBuilderArguments/*!*/ AxBuilderArguments;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(AxBuilderArguments != null);
}
internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments axBuilder, VCExpressionGenerator gen)
: base(axBuilder, gen) {
Contract.Requires(gen != null);
Contract.Requires(axBuilder != null);
this.AxBuilderArguments = axBuilder;
}
// constructor for cloning
internal MapTypeAbstractionBuilderArguments(TypeAxiomBuilderArguments axBuilder, VCExpressionGenerator gen, MapTypeAbstractionBuilderArguments builder)
: base(axBuilder, gen, builder) {
Contract.Requires(builder != null);
Contract.Requires(gen != null);
Contract.Requires(axBuilder != null);
this.AxBuilderArguments = axBuilder;
}
////////////////////////////////////////////////////////////////////////////
protected override void GenSelectStoreFunctions(MapType abstractedType, TypeCtorDecl synonym, out Function/*!*/ select, out Function/*!*/ store) {
//Contract.Requires(synonym != null);
//Contract.Requires(abstractedType != null);
Contract.Ensures(Contract.ValueAtReturn(out select) != null);
Contract.Ensures(Contract.ValueAtReturn(out store) != null);
Contract.Assert(synonym.Name != null);
string/*!*/ baseName = synonym.Name;
int typeParamNum = abstractedType.FreeVariables.Count +
abstractedType.TypeParameters.Count;
int arity = typeParamNum + abstractedType.Arguments.Count;
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.MonomorphicArrays) {
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) {
Contract.Assert(type != null);
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.MonomorphicArrays)
storeTypes[i] = abstractedType;
else
storeTypes[i] = AxBuilder.U;
Contract.Assert(cce.NonNullElements(selectTypes));
Contract.Assert(cce.NonNullElements(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.Count, abstractedType.FreeVariables.Count));
AxBuilder.AddTypeAxiom(GenMapAxiom1(select, store,
abstractedType.TypeParameters.Count, abstractedType.FreeVariables.Count));
}
}
///////////////////////////////////////////////////////////////////////////
// The normal axioms of the theory of arrays (right now without extensionality)
private VCExpr Select(Function select, List /*!*/ types, VCExpr map, List /*!*/ indexes) {
Contract.Requires(map != null);
Contract.Requires(select != null);
Contract.Requires(cce.NonNullElements(indexes));
Contract.Requires(cce.NonNullElements(types));
Contract.Ensures(Contract.Result() != null);
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) {
Contract.Requires(val != null);
Contract.Requires(map != null);
Contract.Requires(store != null);
Contract.Requires(cce.NonNullElements(indexes));
Contract.Requires(cce.NonNullElements(types));
Contract.Ensures(Contract.Result() != null);
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) {
Contract.Requires(select != null);
Contract.Requires(store != null);
Contract.Ensures(Contract.Result() != null);
int arity = select.InParams.Count - 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.Count; i++) {
indexTypes.Add(cce.NonNull(select.InParams[i]).TypedIdent.Type);
}
Contract.Assert(arity == indexTypes.Count);
List /*!*/ indexes = HelperFuns.VarVector("x", indexTypes, Gen);
VCExprVar/*!*/ m = Gen.Variable("m", AxBuilder.U);
Contract.Assert(m != null);
VCExprVar/*!*/ val = Gen.Variable("val", cce.NonNull(select.OutParams[0]).TypedIdent.Type);
Contract.Assert(val != null);
VCExpr/*!*/ storeExpr = Store(store, types, m, indexes, val);
Contract.Assert(storeExpr != null);
VCExpr/*!*/ selectExpr = Select(select, types, storeExpr, indexes);
Contract.Assert(selectExpr != null);
List /*!*/ quantifiedVars = new List ();
quantifiedVars.AddRange(types);
quantifiedVars.Add(val);
quantifiedVars.Add(m);
quantifiedVars.AddRange(indexes);
VCExpr/*!*/ eq = Gen.Eq(selectExpr, val);
Contract.Assert(eq != null);
return Gen.Forall(quantifiedVars, new List (), "mapAx0:" + select.Name, 0, 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) {
Contract.Requires(select != null);
Contract.Requires(store != null);
Contract.Ensures(Contract.Result() != null);
int arity = select.InParams.Count - 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.Count; i++) {
indexTypes.Add(cce.NonNull(select.InParams[i]).TypedIdent.Type);
}
Contract.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);
Contract.Assert(m != null);
VCExprVar/*!*/ val = Gen.Variable("val", cce.NonNull(select.OutParams[0]).TypedIdent.Type);
Contract.Assert(val != null);
VCExpr/*!*/ storeExpr = Store(store, types0, m, indexes0, val);
Contract.Assert(storeExpr != null);
VCExpr/*!*/ selectWithoutStoreExpr = Select(select, types1, m, indexes1);
Contract.Assert(selectWithoutStoreExpr != null);
VCExpr/*!*/ selectExpr = Select(select, types1, storeExpr, indexes1);
Contract.Assert(selectExpr != null);
VCExpr/*!*/ selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr);
Contract.Assert(selectEq != null);
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) {
Contract.Assert(indexesEq != null);
VCExpr/*!*/ matrix = Gen.Or(indexesEq, selectEq);
Contract.Assert(matrix != null);
VCExpr/*!*/ conjunct = Gen.Forall(quantifiedVars, triggers, "mapAx1:" + select.Name + ":" + n, 0, matrix);
Contract.Assert(conjunct != null);
axiom = Gen.AndSimp(axiom, conjunct);
n = n + 1;
}
return axiom;
}
}
//////////////////////////////////////////////////////////////////////////////
public class TypeEraserArguments : TypeEraser {
private readonly TypeAxiomBuilderArguments/*!*/ AxBuilderArguments;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(AxBuilderArguments != null);
}
private OpTypeEraser OpEraserAttr = null;
protected override OpTypeEraser/*!*/ OpEraser {
get {
Contract.Ensures(Contract.Result() != null);
if (OpEraserAttr == null)
OpEraserAttr = new OpTypeEraserArguments(this, AxBuilderArguments, Gen);
return OpEraserAttr;
}
}
public TypeEraserArguments(TypeAxiomBuilderArguments axBuilder, VCExpressionGenerator gen) :base(axBuilder, gen){
Contract.Requires(gen != null);
Contract.Requires(axBuilder != null);
this.AxBuilderArguments = axBuilder;
}
////////////////////////////////////////////////////////////////////////////
public override VCExpr Visit(VCExprQuantifier node, VariableBindings oldBindings) {
Contract.Requires(oldBindings != null);
Contract.Requires(node != null);
Contract.Ensures(Contract.Result() != null);
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);
Contract.Assert(newNode != null);
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) {
Contract.Requires(bindings != null);
Contract.Requires(cce.NonNullElements(typeParams));
Contract.Requires(cce.NonNullElements(newBoundVars));
foreach (TypeVariable/*!*/ tvar in typeParams) {
Contract.Assert(tvar != null);
VCExprVar/*!*/ var = Gen.Variable(tvar.Name, AxBuilder.T);
Contract.Assert(var != null);
newBoundVars.Add(var);
bindings.TypeVariableBindings.Add(tvar, var);
}
}
private VCExpr HandleQuantifier(VCExprQuantifier node, List /*!*/ newBoundVars, VariableBindings bindings){
Contract.Requires(bindings != null);
Contract.Requires(node != null);
Contract.Requires(cce.NonNullElements(newBoundVars));
Contract.Ensures(Contract.Result() != null);
List /*!*/ newTriggers = MutateTriggers(node.Triggers, bindings);
Contract.Assert(cce.NonNullElements(newTriggers));
VCExpr/*!*/ newBody = Mutate(node.Body, bindings);
Contract.Assert(newBody != null);
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;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(AxBuilderArguments != null);
}
public OpTypeEraserArguments(TypeEraserArguments eraser, TypeAxiomBuilderArguments axBuilder, VCExpressionGenerator gen) :base(eraser, axBuilder, gen){
Contract.Requires(gen != null);
Contract.Requires(axBuilder != null);
Contract.Requires(eraser != null);
this.AxBuilderArguments = axBuilder;
}
////////////////////////////////////////////////////////////////////////////
private VCExpr AssembleOpExpression(OpTypesPair opTypes, IEnumerable /*!*/ oldArgs, VariableBindings bindings){
Contract.Requires(bindings != null);
Contract.Requires(cce.NonNullElements(oldArgs));
Contract.Ensures(Contract.Result() != null);
// 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){
Contract.Assert(newArgs != null);
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) {
Contract.Assert(arg != null);
newArgs.Add(AxBuilder.Cast(Eraser.Mutate(arg, bindings),
cce.NonNull(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){
Contract.Requires(node != null);
List /*!*/ originalTypes = new List ();
foreach (VCExpr/*!*/ expr in node) {
Contract.Assert(expr != null);
originalTypes.Add(expr.Type);
}
originalTypes.AddRange(node.TypeArguments);
return new OpTypesPair (node.Op, originalTypes);
}
private VCExpr EqualTypes(Type t0, Type t1, VariableBindings bindings){
Contract.Requires(bindings != null);
Contract.Requires(t1 != null);
Contract.Requires(t0 != null);
Contract.Ensures(Contract.Result() != null);
if (t0.Equals(t1))
return VCExpressionGenerator.True;
VCExpr/*!*/ t0Expr = AxBuilder.Type2Term(t0, bindings.TypeVariableBindings);
Contract.Assert(t0Expr != null);
VCExpr/*!*/ t1Expr = AxBuilder.Type2Term(t1, bindings.TypeVariableBindings);
Contract.Assert(t1Expr != null);
return Gen.Eq(t0Expr, t1Expr);
}
///////////////////////////////////////////////////////////////////////////
public override VCExpr VisitEqOp(VCExprNAry node, VariableBindings bindings) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
// 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) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
// 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) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
// 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) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
OpTypesPair originalOpTypes = OriginalOpTypes(node);
OpTypesPair newOpTypes;
if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) {
MapType/*!*/ rawType = node[0].Type.AsMap;
Contract.Assert(rawType != null);
List/*!*/ abstractionInstantiation;
Function/*!*/ select =
AxBuilder.MapTypeAbstracter.Select(rawType, out abstractionInstantiation);
Contract.Assert(abstractionInstantiation != null);
newOpTypes = TypesPairForSelectStore(node, select, abstractionInstantiation);
NewOpCache.Add(originalOpTypes, newOpTypes);
}
return AssembleOpExpression(newOpTypes, node, bindings);
}
public override VCExpr VisitStoreOp(VCExprNAry node, VariableBindings bindings) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
OpTypesPair originalOpTypes = OriginalOpTypes(node);
OpTypesPair newOpTypes;
if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) {
MapType/*!*/ rawType = node[0].Type.AsMap;
List/*!*/ 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
List/*!*/ abstractionInstantiation) {
Contract.Requires(node != null);
Contract.Requires(untypedOp != null);
Contract.Requires(abstractionInstantiation != null);
List /*!*/ inferredTypeArgs = new List ();
foreach (Type/*!*/ t in node.TypeArguments){Contract.Assert(t != null);
// inferredTypeArgs.Add(AxBuilder.MapTypeAbstracter.AbstractMapTypeRecursively(t));
inferredTypeArgs.Add(t);}
foreach (Type/*!*/ t in abstractionInstantiation) {
Contract.Assert(t != null);
inferredTypeArgs.Add(t);}
Contract.Assert(untypedOp.InParams.Count == inferredTypeArgs.Count + node.Arity);
return new OpTypesPair (Gen.BoogieFunctionOp(untypedOp), inferredTypeArgs);
}
///////////////////////////////////////////////////////////////////////////
public override VCExpr VisitBoogieFunctionOp(VCExprNAry node, VariableBindings bindings) {
Contract.Requires((bindings != null));
Contract.Requires((node != null));
Contract.Ensures(Contract.Result() != null);
OpTypesPair originalOpTypes = OriginalOpTypes(node);
OpTypesPair newOpTypes;
if (!NewOpCache.TryGetValue(originalOpTypes, out newOpTypes)) {
Function/*!*/ oriFun = ((VCExprBoogieFunctionOp)node.Op).Func;
Contract.Assert(oriFun != null);
List /*!*/ inferredTypeArgs = new List ();
foreach (Type/*!*/ t in node.TypeArguments){Contract.Assert(t != null);
// 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;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Op != null);
Contract.Invariant(cce.NonNullElements(Types));
}
public OpTypesPair(VCExprOp op, List /*!*/ types) {
Contract.Requires(op != null);
Contract.Requires(cce.NonNullElements(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;
}
}
}
}