//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.Text; using System.IO; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Diagnostics.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; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Fun != null); Contract.Invariant(cce.NonNullElements(ImplicitTypeParams)); Contract.Invariant(cce.NonNullElements(ExplicitTypeParams)); } public UntypedFunction(Function/*!*/ fun, List/*!*/ implicitTypeParams, List/*!*/ explicitTypeParams) { Contract.Requires(fun != null); Contract.Requires(cce.NonNullElements(implicitTypeParams)); Contract.Requires(cce.NonNullElements(explicitTypeParams)); Fun = fun; ImplicitTypeParams = implicitTypeParams; ExplicitTypeParams = explicitTypeParams; } } public class TypeAxiomBuilderPremisses : TypeAxiomBuilderIntBoolU { public TypeAxiomBuilderPremisses(VCExpressionGenerator gen) : base(gen) { Contract.Requires(gen != null); TypeFunction = HelperFuns.BoogieFunction("dummy", Type.Int); Typed2UntypedFunctions = new Dictionary(); MapTypeAbstracterAttr = null; } // constructor to allow cloning [NotDelayed] internal TypeAxiomBuilderPremisses(TypeAxiomBuilderPremisses builder) : base(builder) { Contract.Requires(builder != null); TypeFunction = builder.TypeFunction; Typed2UntypedFunctions = new Dictionary(builder.Typed2UntypedFunctions); MapTypeAbstracterAttr = builder.MapTypeAbstracterAttr == null ? null : new MapTypeAbstractionBuilderPremisses(this, builder.Gen, builder.MapTypeAbstracterAttr); } public override Object Clone() { Contract.Ensures(Contract.Result() != null); 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) { //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); Contract.Assert(cce.NonNullElements(triggers)); Contract.Assert(var != null); Contract.Assert(eq != null); VCExpr/*!*/ premiss; if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) premiss = VCExpressionGenerator.True; else premiss = GenVarTypeAxiom(var, cce.NonNull(castFromU.OutParams[0]).TypedIdent.Type, // we don't have any bindings available new Dictionary()); VCExpr/*!*/ matrix = Gen.ImpliesSimp(premiss, eq); Contract.Assert(matrix != null); return Gen.Forall(HelperFuns.ToList(var), triggers, "cast:" + castFromU.Name, -1, matrix); } protected override VCExpr GenCastTypeAxioms(Function castToU, Function castFromU) { //Contract.Requires(castFromU != null); //Contract.Requires(castToU != null); Contract.Ensures(Contract.Result() != null); Type/*!*/ fromType = cce.NonNull(castToU.InParams[0]).TypedIdent.Type; return GenFunctionAxiom(castToU, new List(), new List(), HelperFuns.ToList(fromType), fromType); } private MapTypeAbstractionBuilderPremisses MapTypeAbstracterAttr; internal override MapTypeAbstractionBuilder/*!*/ MapTypeAbstracter { get { Contract.Ensures(Contract.Result() != null); if (MapTypeAbstracterAttr == null) MapTypeAbstracterAttr = new MapTypeAbstractionBuilderPremisses(this, Gen); return MapTypeAbstracterAttr; } } internal MapTypeAbstractionBuilderPremisses/*!*/ MapTypeAbstracterPremisses { get { Contract.Ensures(Contract.Result() != null); return (MapTypeAbstractionBuilderPremisses)MapTypeAbstracter; } } //////////////////////////////////////////////////////////////////////////// // function that maps individuals to their type // the field is overwritten with its actual value in "Setup" private Function/*!*/ TypeFunction; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(TypeFunction != null); } public VCExpr TypeOf(VCExpr expr) { Contract.Requires(expr != null); Contract.Ensures(Contract.Result() != null); 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) { Contract.Requires(typeParams != null); Contract.Requires(cce.NonNullElements(oldBoundVars)); Contract.Requires(bindings != null); Contract.Ensures(cce.NonNullElements(Contract.Result>())); // type variables are replaced with ordinary variables that are bound using a // let-expression if (addTypeVarsToBindings) { foreach (TypeVariable/*!*/ tvar in typeParams) { Contract.Assert(tvar != null); 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) { Contract.Requires(cce.NonNullElements(typeVarBindings)); Contract.Requires(typePremisses != null); Contract.Requires(body != null); Contract.Ensures(Contract.Result() != null); 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) { Contract.Requires(cce.NonNullElements(vars)); Contract.Requires(cce.NonNullElements(types)); Contract.Requires(cce.NonNullElements(concreteTypeSources)); Contract.Requires(bindings != null); Contract.Ensures(cce.NonNullElements(Contract.Result>())); List/*!*/ typeParamBindings = new List(); foreach (TypeVariable/*!*/ var in vars) { Contract.Assert(var != null); 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) { Contract.Requires(var != null); Contract.Requires(cce.NonNullElements(types)); Contract.Requires(cce.NonNullElements(concreteTypeSources)); List allExtractors = TypeVarExtractors(var, types, concreteTypeSources); Contract.Assert(cce.NonNullElements(allExtractors)); 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) { Contract.Requires(var != null); Contract.Requires(cce.NonNullElements(types)); Contract.Requires(cce.NonNullElements(concreteTypeSources)); Contract.Requires((types.Count == concreteTypeSources.Count)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); 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) { Contract.Requires(innerTerm != null); Contract.Requires(completeType != null); Contract.Requires(var != null); Contract.Requires(cce.NonNullElements(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.Count > 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.Count; ++i) { VCExpr/*!*/ newInnerTerm = Gen.Function(repr.Dtors[i], innerTerm); Contract.Assert(newInnerTerm != null); 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; [ContractInvariantMethod] void Typed2UntypedFunctionsInvariantMethod() { Contract.Invariant(Typed2UntypedFunctions != null); } // distinguish between implicit and explicit type parameters internal static void SeparateTypeParams(List/*!*/ valueArgumentTypes, List/*!*/ allTypeParams, out List/*!*/ implicitParams, out List/*!*/ explicitParams) { Contract.Requires(cce.NonNullElements(valueArgumentTypes)); Contract.Requires(allTypeParams != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out implicitParams))); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out explicitParams))); List/*!*/ varsInInParamTypes = new List(); foreach (Type/*!*/ t in valueArgumentTypes) { Contract.Assert(t != null); varsInInParamTypes.AppendWithoutDups(t.FreeVariables); } implicitParams = new List(allTypeParams.Count); explicitParams = new List(allTypeParams.Count); foreach (TypeVariable/*!*/ var in allTypeParams) { Contract.Assert(var != null); if (varsInInParamTypes.Contains(var)) implicitParams.Add(var); else explicitParams.Add(var); } implicitParams.TrimExcess(); explicitParams.TrimExcess(); } internal UntypedFunction Typed2Untyped(Function fun) { Contract.Requires(fun != null); UntypedFunction 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) && fun.TypeParameters.Count == 0) { res = new UntypedFunction(fun, new List(), new List()); } else { List/*!*/ argTypes = new List(); foreach (Variable/*!*/ v in fun.InParams) { Contract.Assert(v != null); argTypes.Add(v.TypedIdent.Type); } List/*!*/ implicitParams, explicitParams; SeparateTypeParams(argTypes, fun.TypeParameters, out implicitParams, out explicitParams); Type[]/*!*/ types = new Type[explicitParams.Count + fun.InParams.Count + 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.Count; ++i, ++j) types[i] = TypeAfterErasure(cce.NonNull(fun.InParams[j]).TypedIdent.Type); types[types.Length - 1] = TypeAfterErasure(cce.NonNull(fun.OutParams[0]).TypedIdent.Type); Function/*!*/ untypedFun = HelperFuns.BoogieFunction(fun.Name, types); Contract.Assert(untypedFun != null); 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) { Contract.Requires(originalFun != null); Contract.Ensures(Contract.Result() != null); List/*!*/ originalInTypes = new List(originalFun.InParams.Count); foreach (Formal/*!*/ f in originalFun.InParams) originalInTypes.Add(f.TypedIdent.Type); return GenFunctionAxiom(fun.Fun, fun.ImplicitTypeParams, fun.ExplicitTypeParams, originalInTypes, cce.NonNull(originalFun.OutParams[0]).TypedIdent.Type); } internal VCExpr/*!*/ GenFunctionAxiom(Function/*!*/ fun, List/*!*/ implicitTypeParams, List/*!*/ explicitTypeParams, List/*!*/ originalInTypes, Type/*!*/ originalResultType) { Contract.Requires(cce.NonNullElements(implicitTypeParams)); Contract.Requires(fun != null); Contract.Requires(cce.NonNullElements(explicitTypeParams)); Contract.Requires(cce.NonNullElements(originalInTypes)); Contract.Requires(originalResultType != null); Contract.Requires(originalInTypes.Count + explicitTypeParams.Count == fun.InParams.Count); Contract.Ensures(Contract.Result() != null); if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None) { return VCExpressionGenerator.True; } List/*!*/ typedInputVars = new List(originalInTypes.Count); int i = 0; foreach (Type/*!*/ t in originalInTypes) { Contract.Assert(t != null); 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) { Contract.Assert(var != null); 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) { Contract.Assert(var != null); Type/*!*/ newType = TypeAfterErasure(var.Type); Contract.Assert(newType != null); VCExprVar/*!*/ newVar = Gen.Variable(var.Name, newType); Contract.Assert(newVar != null); boundVars.Add(newVar); bindings.VCExprVarBindings.Add(var, newVar); } List typeVarBindings = GenTypeParamBindings(implicitTypeParams, typedInputVars, bindings, true); Contract.Assert(cce.NonNullElements(typeVarBindings)); VCExpr/*!*/ funApp = Gen.Function(fun, HelperFuns.ToVCExprList(boundVars)); Contract.Assert(funApp != null); VCExpr/*!*/ conclusion = Gen.Eq(TypeOf(funApp), Type2Term(originalResultType, bindings.TypeVariableBindings)); Contract.Assert(conclusion != null); 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))); Contract.Assert(cce.NonNullElements(triggers)); return Gen.Forall(boundVars, triggers, "funType:" + fun.Name, -1, conclusionWithPremisses); } else { return conclusionWithPremisses; } } //////////////////////////////////////////////////////////////////////////// protected override void AddVarTypeAxiom(VCExprVar var, Type originalType) { //Contract.Requires(originalType != null); //Contract.Requires(var != null); 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) { Contract.Requires(var != null); Contract.Requires(originalType != null); Contract.Requires(cce.NonNullDictionaryAndValues(varMapping)); Contract.Ensures(Contract.Result() != null); 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; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(AxBuilderPremisses != null); } internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses axBuilder, VCExpressionGenerator gen) : base(axBuilder, gen) { Contract.Requires(gen != null); Contract.Requires(axBuilder != null); this.AxBuilderPremisses = axBuilder; } // constructor for cloning internal MapTypeAbstractionBuilderPremisses(TypeAxiomBuilderPremisses axBuilder, VCExpressionGenerator gen, MapTypeAbstractionBuilderPremisses builder) : base(axBuilder, gen, builder) { Contract.Requires(builder != null); Contract.Requires(gen != null); Contract.Requires(axBuilder != null); 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) { Contract.Requires(type != null); Contract.Ensures(Contract.Result>() != null); 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) { Contract.Assert(var != null); res.Add(type.TypeParameters.IndexOf(var)); } explicitSelectTypeParamsCache.Add(type, res); } return cce.NonNull(res); } private IDictionary/*!*/>/*!*/ explicitSelectTypeParamsCache = new Dictionary/*!*/>(); [ContractInvariantMethod] void ObjectInvarant() { Contract.Invariant(cce.NonNullDictionaryAndValues(explicitSelectTypeParamsCache)); } //////////////////////////////////////////////////////////////////////////// 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); 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 Contract.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) { Contract.Requires(abstractedType != null); Contract.Requires(synonymDecl != null); Contract.Ensures(Contract.ValueAtReturn(out mapTypeSynonym) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out typeParams))); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out originalIndexTypes))); typeParams = new List(); typeParams.AddRange(abstractedType.TypeParameters); typeParams.AddRange(abstractedType.FreeVariables); originalIndexTypes = new List(abstractedType.Arguments.Count + 1); List/*!*/ mapTypeParams = new List(); foreach (TypeVariable/*!*/ var in abstractedType.FreeVariables) { Contract.Assert(var != null); mapTypeParams.Add(var); } if (CommandLineOptions.Clo.MonomorphicArrays) 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) { Contract.Requires(cce.NonNullElements(originalTypeParams)); Contract.Requires(cce.NonNullElements(originalInTypes)); Contract.Requires(originalResult != null); Contract.Requires(name != null); Contract.Ensures(Contract.Result() != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out implicitTypeParams))); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out 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, new List(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) { Contract.Assert(type != null); 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); Contract.Assert(res != null); 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) { Contract.Requires(select != null); Contract.Requires(cce.NonNullElements(typeParams)); Contract.Requires(map != null); Contract.Requires(cce.NonNullElements(indexes)); Contract.Ensures(Contract.Result() != null); 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) { Contract.Requires(val != null); Contract.Requires(map != null); Contract.Requires(store != null); Contract.Requires(cce.NonNullElements(indexes)); Contract.Ensures(Contract.Result() != null); 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) { Contract.Requires(mapResult != null); Contract.Requires(store != null); Contract.Requires(select != null); Contract.Requires(cce.NonNullElements(implicitTypeParamsSelect)); Contract.Requires(cce.NonNullElements(originalInTypes)); Contract.Requires(cce.NonNullElements(explicitTypeParamsSelect)); Contract.Ensures(Contract.Result() != null); int arity = store.InParams.Count - 2; List inParams = new List(); List quantifiedVars = new List(store.InParams.Count); 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.Count - 1; i++) { origIndexTypes.Add(originalInTypes[i]); indexTypes.Add(cce.NonNull(store.InParams[i]).TypedIdent.Type); } Contract.Assert(arity == indexTypes.Count); List typedArgs = HelperFuns.VarVector("arg", origIndexTypes, Gen); Contract.Assert(cce.NonNullElements(typedArgs)); List indexes = HelperFuns.VarVector("x", indexTypes, Gen); Contract.Assert(cce.NonNullElements(indexes)); Contract.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", cce.NonNull(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); Contract.Assert(storeExpr != null); VCExpr/*!*/ selectExpr = Select(select, typeParams, storeExpr, indexes); Contract.Assert(selectExpr != null); // 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); Contract.Assert(cce.NonNullElements(letBindings_Implicit)); // 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); Contract.Assert(cce.NonNullElements(letBindings_Explicit)); // generate: select(store(m, indices, val)) == val VCExpr/*!*/ eq = Gen.Eq(selectExpr, val); Contract.Assert(eq != null); // generate: type(val) == T, where T is the type of val VCExpr/*!*/ ante = Gen.Eq( AxBuilderPremisses.TypeOf(val), AxBuilderPremisses.Type2Term(mapResult, bindings.TypeVariableBindings)); Contract.Assert(ante != null); VCExpr body; if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.None || !AxBuilder.U.Equals(cce.NonNull(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, 0, body); } private VCExpr GenMapAxiom1(Function select, Function store, Type mapResult, List/*!*/ explicitSelectParams) { Contract.Requires(mapResult != null); Contract.Requires(store != null); Contract.Requires(select != null); Contract.Requires(cce.NonNullElements(explicitSelectParams)); Contract.Ensures(Contract.Result() != null); int arity = store.InParams.Count - 2; List indexTypes = new List(); for (int i = 1; i < store.InParams.Count - 1; i++) { indexTypes.Add(cce.NonNull(store.InParams[i]).TypedIdent.Type); } Contract.Assert(indexTypes.Count == arity); List/*!*/ indexes0 = HelperFuns.VarVector("x", indexTypes, Gen); Contract.Assert(cce.NonNullElements(indexes0)); List/*!*/ indexes1 = HelperFuns.VarVector("y", indexTypes, Gen); Contract.Assert(cce.NonNullElements(indexes1)); 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); // extract the explicit type parameters from the actual result type ... VCExprVar/*!*/ typedVal = Gen.Variable("val", mapResult); Contract.Assert(typedVal != null); VariableBindings/*!*/ bindings = new VariableBindings(); bindings.VCExprVarBindings.Add(typedVal, val); List/*!*/ letBindings = AxBuilderPremisses.GenTypeParamBindings(explicitSelectParams, HelperFuns.ToList(typedVal), bindings, true); Contract.Assert(cce.NonNullElements(letBindings)); // ... 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) { Contract.Assert(var != null); VCExprVar/*!*/ newVar = (VCExprVar)bindings.TypeVariableBindings[var]; Contract.Assert(newVar != null); typeParams.Add(newVar); typeParamsExpr.Add(newVar); } VCExpr/*!*/ storeExpr = Store(store, m, indexes0, val); Contract.Assert(storeExpr != null); VCExpr/*!*/ selectWithoutStoreExpr = Select(select, typeParamsExpr, m, indexes1); Contract.Assert(selectWithoutStoreExpr != null); VCExpr/*!*/ selectExpr = Select(select, typeParamsExpr, storeExpr, indexes1); Contract.Assert(selectExpr != null); VCExpr/*!*/ selectEq = Gen.Eq(selectExpr, selectWithoutStoreExpr); Contract.Assert(selectEq != null); 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(); Contract.Assert(cce.NonNullElements(triggers)); VCExpr/*!*/ axiom = VCExpressionGenerator.True; Contract.Assert(axiom != null); // 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, 0, matrix); Contract.Assert(indexesEq != null); Contract.Assert(matrix != null); Contract.Assert(conjunct != null); 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) { Contract.Assert(b != null); 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, 0, matrix2); axiom = Gen.AndSimp(axiom, conjunct2); return axiom; } } ///////////////////////////////////////////////////////////////////////////// public class TypeEraserPremisses : TypeEraser { private readonly TypeAxiomBuilderPremisses/*!*/ AxBuilderPremisses; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(AxBuilderPremisses != null); } private OpTypeEraser OpEraserAttr = null; protected override OpTypeEraser/*!*/ OpEraser { get { Contract.Ensures(Contract.Result() != null); if (OpEraserAttr == null) OpEraserAttr = new OpTypeEraserPremisses(this, AxBuilderPremisses, Gen); return OpEraserAttr; } } public TypeEraserPremisses(TypeAxiomBuilderPremisses axBuilder, VCExpressionGenerator gen) : base(axBuilder, gen) { Contract.Requires(gen != null); Contract.Requires(axBuilder != null); this.AxBuilderPremisses = 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(); // 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) { Contract.Assert(e != null); 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); Contract.Assert(cce.NonNullElements(newBoundVars)); VCExpr/*!*/ newNode = HandleQuantifier(node, occurringVars, newBoundVars, bindings); Contract.Assert(newNode != null); 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) { Contract.Requires(cce.NonNullElements(oldBoundVars)); Contract.Requires(cce.NonNullElements(newBoundVars)); Contract.Requires(cce.NonNullDictionaryAndValues(typeVarTranslation)); Contract.Requires(cce.NonNullElements(typeVarBindings)); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out triggers))); Contract.Ensures(Contract.Result() != null); // 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) { Contract.Assert(binding != null); typeParamSubstitution[binding.V] = binding.E; } SubstitutingVCExprVisitor/*!*/ substituter = new SubstitutingVCExprVisitor(Gen); Contract.Assert(substituter != null); List/*!*/ typePremisses = new List(newBoundVars.Count); triggers = new List(newBoundVars.Count); for (int i = 0; i < newBoundVars.Count; ++i) { VCExprVar/*!*/ oldVar = oldBoundVars[i]; Contract.Assert(oldVar != null); VCExprVar/*!*/ newVar = newBoundVars[i]; Contract.Assert(newVar != null); VCExpr/*!*/ typePremiss = AxBuilderPremisses.GenVarTypeAxiom(newVar, oldVar.Type, typeVarTranslation); Contract.Assert(typePremiss != null); 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) { Contract.Requires(expr != null); if (expr.Equals(VCExpressionGenerator.True)) return true; if (expr is VCExprNAry) { VCExprNAry/*!*/ naryExpr = (VCExprNAry)expr; Contract.Assert(naryExpr != null); 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) { Contract.Requires(bindings != null); Contract.Requires(node != null); Contract.Requires(cce.NonNullElements(occurringVars/*!*/)); Contract.Requires(cce.NonNullElements(newBoundVars)); Contract.Ensures(Contract.Result() != null); List/*!*/ typeVarBindings = AxBuilderPremisses.GenTypeParamBindings(node.TypeParameters, occurringVars, bindings, true); Contract.Assert(typeVarBindings != null); // 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) { Contract.Assert(var != null); if (typeVarBindings.All(b => !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) { Contract.Assert(oldVar != null); 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); Contract.Assert(cce.NonNullElements(furtherTriggers)); Contract.Assert(typePremisses != null); List/*!*/ newTriggers = MutateTriggers(node.Triggers, bindings); Contract.Assert(cce.NonNullElements(newTriggers)); newTriggers.AddRange(furtherTriggers); newTriggers = AddLets2Triggers(newTriggers, typeVarBindings); VCExpr/*!*/ newBody = Mutate(node.Body, bindings); Contract.Assert(newBody != null); // 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)); Contract.Assert(bodyWithPremisses != null); if (newBoundVars.Count == 0) // might happen that no bound variables are left return bodyWithPremisses; foreach (VCExprVar/*!*/ v in newBoundVars) { Contract.Assert(v != null); 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) { Contract.Requires(cce.NonNullElements(triggers/*!*/)); Contract.Requires(cce.NonNullElements(typeVarBindings)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); List/*!*/ triggersWithLets = new List(triggers.Count); foreach (VCTrigger/*!*/ t in triggers) { Contract.Assert(t != null); List/*!*/ exprsWithLets = new List(t.Exprs.Count); bool changed = false; foreach (VCExpr/*!*/ e in t.Exprs) { Contract.Assert(e != null); Dictionary/*!*/ freeVars = FreeVariableCollector.FreeTermVariables(e); Contract.Assert(freeVars != null && cce.NonNullElements(freeVars.Keys)); if (typeVarBindings.Any(b => 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; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(AxBuilderPremisses != null); } public OpTypeEraserPremisses(TypeEraserPremisses eraser, TypeAxiomBuilderPremisses axBuilder, VCExpressionGenerator gen) : base(eraser, axBuilder, gen) { Contract.Requires(gen != null); Contract.Requires(axBuilder != null); Contract.Requires(eraser != null); this.AxBuilderPremisses = axBuilder; } private VCExpr HandleFunctionOp(Function newFun, List/*!*/ typeArgs/*!*/, IEnumerable/*!*/ oldArgs, VariableBindings bindings) { Contract.Requires(bindings != null); Contract.Requires(newFun != null); Contract.Requires(cce.NonNullElements(typeArgs/*!*/)); 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(typeArgs.Count); // translate the explicit type arguments foreach (Type/*!*/ t in typeArgs) { Contract.Assert(t != null); newArgs.Add(AxBuilder.Type2Term(t, bindings.TypeVariableBindings)); } // recursively translate the value arguments foreach (VCExpr/*!*/ arg in oldArgs) { Contract.Assert(arg != null); Type/*!*/ newType = cce.NonNull(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) { Contract.Requires(node != null); Contract.Requires(bindings != null); Contract.Ensures(Contract.Result() != null); MapType/*!*/ mapType = node[0].Type.AsMap; Contract.Assert(mapType != null); List/*!*/ instantiations; // not used Function/*!*/ select = AxBuilder.MapTypeAbstracter.Select(mapType, out instantiations); Contract.Assert(select != null); List/*!*/ explicitTypeParams = AxBuilderPremisses.MapTypeAbstracterPremisses .ExplicitSelectTypeParams(mapType); Contract.Assert(select.InParams.Count == 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) { Contract.Requires(bindings != null); Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); List/*!*/ instantiations; // not used Function/*!*/ store = AxBuilder.MapTypeAbstracter.Store(node[0].Type.AsMap, out instantiations); Contract.Assert(store != null); return HandleFunctionOp(store, // the store function never has explicit // type parameters new List(), node, bindings); } public override VCExpr VisitBoogieFunctionOp(VCExprNAry node, VariableBindings bindings) { Contract.Requires(bindings != null); Contract.Requires(node != null); Contract.Ensures(Contract.Result() != null); Function/*!*/ oriFun = ((VCExprBoogieFunctionOp)node.Op).Func; Contract.Assert(oriFun != null); UntypedFunction untypedFun = AxBuilderPremisses.Typed2Untyped(oriFun); Contract.Assert(untypedFun.Fun.InParams.Count == 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, List allTypeParams, List/*!*/ explicitTypeParams) { Contract.Requires(allTypeParams != null); Contract.Requires(node != null); Contract.Requires(cce.NonNullElements(explicitTypeParams)); Contract.Ensures(cce.NonNullElements(Contract.Result>())); List/*!*/ res = new List(explicitTypeParams.Count); foreach (TypeVariable/*!*/ var in explicitTypeParams) { Contract.Assert(var != null); // this lookup could be optimised res.Add(node.TypeArguments[allTypeParams.IndexOf(var)]); } return res; } } }