//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.Text; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Numerics; using System.Linq; using Microsoft.Boogie; using System.Diagnostics; namespace Microsoft.Dafny { public class Program { [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(FullName != null); Contract.Invariant(DefaultModule != null); } public readonly string FullName; public List Modules; // filled in during resolution. // Resolution essentially flattens the module hierarchy, for // purposes of translation and compilation. public List CompileModules; // filled in during resolution. // Contains the definitions to be used for compilation. public readonly ModuleDecl DefaultModule; public readonly ModuleDefinition DefaultModuleDef; public readonly BuiltIns BuiltIns; public readonly List TranslationTasks; public readonly ErrorReporter reporter; public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns, ErrorReporter reporter) { Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(module is LiteralModuleDecl); Contract.Requires(reporter != null); FullName = name; DefaultModule = module; DefaultModuleDef = (DefaultModuleDecl)((LiteralModuleDecl)module).ModuleDef; BuiltIns = builtIns; this.reporter = reporter; Modules = new List(); CompileModules = new List(); TranslationTasks = new List(); } public string Name { get { try { return System.IO.Path.GetFileName(FullName); } catch (ArgumentException) { return FullName; } } } } public class Include : IComparable { public readonly IToken tok; public readonly string filename; public readonly string fullPath; public Include(IToken tok, string theFilename, string fullPath) { this.tok = tok; this.filename = theFilename; this.fullPath = fullPath; } public int CompareTo(object obj) { var i = obj as Include; if (i != null) { return this.fullPath.CompareTo(i.fullPath); } else { throw new NotImplementedException(); } } } public class BuiltIns { public readonly ModuleDefinition SystemModule = new ModuleDefinition(Token.NoToken, "_System", false, false, /*isExclusiveRefinement:*/ false, null, null, null, true); readonly Dictionary arrayTypeDecls = new Dictionary(); readonly Dictionary arrowTypeDecls = new Dictionary(); readonly Dictionary tupleTypeDecls = new Dictionary(); public readonly ClassDecl ObjectDecl; public BuiltIns() { SystemModule.Height = -1; // the system module doesn't get a height assigned later, so we set it here to something below everything else // create type synonym 'string' var str = new TypeSynonymDecl(Token.NoToken, "string", new List(), SystemModule, new SeqType(new CharType()), null); SystemModule.TopLevelDecls.Add(str); // create class 'object' ObjectDecl = new ClassDecl(Token.NoToken, "object", SystemModule, new List(), new List(), DontCompile(), null); SystemModule.TopLevelDecls.Add(ObjectDecl); // add one-dimensional arrays, since they may arise during type checking // Arrays of other dimensions may be added during parsing as the parser detects the need for these UserDefinedType tmp = ArrayType(1, Type.Int, true); // Arrow types of other dimensions may be added during parsing as the parser detects the need for these. For the 0-arity // arrow type, the resolver adds a Valid() predicate for iterators, whose corresponding arrow type is conveniently created here. CreateArrowTypeDecl(0); // Note, in addition to these types, the _System module contains tuple types. These tuple types are added to SystemModule // by the parser as the parser detects the need for these. } private Attributes DontCompile() { var flse = Expression.CreateBoolLiteral(Token.NoToken, false); return new Attributes("compile", new List() { flse }, null); } public UserDefinedType ArrayType(int dims, Type arg, bool allowCreationOfNewClass) { Contract.Requires(1 <= dims); Contract.Requires(arg != null); return ArrayType(Token.NoToken, dims, new List() { arg }, allowCreationOfNewClass); } public UserDefinedType ArrayType(IToken tok, int dims, List optTypeArgs, bool allowCreationOfNewClass) { Contract.Requires(tok != null); Contract.Requires(1 <= dims); Contract.Requires(optTypeArgs == null || optTypeArgs.Count > 0); // ideally, it is 1, but more will generate an error later, and null means it will be filled in automatically Contract.Ensures(Contract.Result() != null); UserDefinedType udt = new UserDefinedType(tok, ArrayClassName(dims), optTypeArgs); if (allowCreationOfNewClass && !arrayTypeDecls.ContainsKey(dims)) { ArrayClassDecl arrayClass = new ArrayClassDecl(dims, SystemModule, DontCompile()); for (int d = 0; d < dims; d++) { string name = dims == 1 ? "Length" : "Length" + d; string compiledName = dims == 1 ? "Length" : "GetLength(" + d + ")"; Field len = new SpecialField(Token.NoToken, name, compiledName, "new BigInteger(", ")", false, false, false, Type.Int, null); len.EnclosingClass = arrayClass; // resolve here arrayClass.Members.Add(len); } arrayTypeDecls.Add(dims, arrayClass); SystemModule.TopLevelDecls.Add(arrayClass); } return udt; } public static string ArrayClassName(int dims) { Contract.Requires(1 <= dims); if (dims == 1) { return "array"; } else { return "array" + dims; } } /// /// Idempotently add an arrow type with arity 'arity' to the system module. /// public void CreateArrowTypeDecl(int arity) { Contract.Requires(0 <= arity); if (!arrowTypeDecls.ContainsKey(arity)) { IToken tok = Token.NoToken; var tps = Util.Map(Enumerable.Range(0, arity + 1), x => new TypeParameter(tok, "T" + x)); var tys = tps.ConvertAll(tp => (Type)(new UserDefinedType(tp))); var args = Util.Map(Enumerable.Range(0, arity), i => new Formal(tok, "x" + i, tys[i], true, false)); var argExprs = args.ConvertAll(a => (Expression)new IdentifierExpr(tok, a.Name) { Var = a, Type = a.Type }); var readsIS = new FunctionCallExpr(tok, "reads", new ImplicitThisExpr(tok), tok, argExprs) { Type = new SetType(true, new ObjectType()), }; var readsFrame = new List { new FrameExpression(tok, readsIS, null) }; var req = new Function(tok, "requires", false, false, true, new List(), args, Type.Bool, new List(), readsFrame, new List(), new Specification(new List(), null), null, null, null); var reads = new Function(tok, "reads", false, false, true, new List(), args, new SetType(true, new ObjectType()), new List(), readsFrame, new List(), new Specification(new List(), null), null, null, null); readsIS.Function = reads; // just so we can really claim the member declarations are resolved readsIS.TypeArgumentSubstitutions = Util.Dict(tps, tys); // ditto var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile(), null); arrowTypeDecls.Add(arity, arrowDecl); SystemModule.TopLevelDecls.Add(arrowDecl); } } public TupleTypeDecl TupleType(IToken tok, int dims, bool allowCreationOfNewType) { Contract.Requires(tok != null); Contract.Requires(0 <= dims); Contract.Ensures(Contract.Result() != null); TupleTypeDecl tt; if (!tupleTypeDecls.TryGetValue(dims, out tt)) { Contract.Assume(allowCreationOfNewType); // the parser should ensure that all needed tuple types exist by the time of resolution tt = new TupleTypeDecl(dims, SystemModule); tupleTypeDecls.Add(dims, tt); SystemModule.TopLevelDecls.Add(tt); } return tt; } public static string TupleTypeName(int dims) { Contract.Requires(0 <= dims); return "_tuple#" + dims; } public static bool IsTupleTypeName(string s) { Contract.Requires(s != null); return s.StartsWith("_tuple#"); } public const string TupleTypeCtorName = "_#Make"; // the printer wants this name to be uniquely recognizable } public class Attributes { [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Name != null); Contract.Invariant(cce.NonNullElements(Args)); } public string Name; /*Frozen*/ public readonly List Args; public readonly Attributes Prev; public Attributes(string name, [Captured] List args, Attributes prev) { Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(args)); Name = name; Args = args; Prev = prev; } public static IEnumerable SubExpressions(Attributes attrs) { return attrs.AsEnumerable().SelectMany(aa => attrs.Args); } public static bool Contains(Attributes attrs, string nm) { Contract.Requires(nm != null); return attrs.AsEnumerable().Any(aa => aa.Name == nm); } /// /// Returns true if "nm" is a specified attribute. If it is, then: /// - if the attribute is {:nm true}, then value==true /// - if the attribute is {:nm false}, then value==false /// - if the attribute is anything else, then value returns as whatever it was passed in as. /// [Pure] public static bool ContainsBool(Attributes attrs, string nm, ref bool value) { Contract.Requires(nm != null); foreach (var attr in attrs.AsEnumerable()) { if (attr.Name == nm) { if (attr.Args.Count == 1) { var arg = attr.Args[0] as LiteralExpr; if (arg != null && arg.Value is bool) { value = (bool)arg.Value; } } return true; } } return false; } /// /// Checks whether a Boolean attribute has been set on the declaration itself, /// the enclosing class, or any enclosing module. Settings closer to the declaration /// override those further away. /// public static bool ContainsBoolAtAnyLevel(MemberDecl decl, string attribName) { bool setting = true; if (Attributes.ContainsBool(decl.Attributes, attribName, ref setting)) { return setting; } if (Attributes.ContainsBool(decl.EnclosingClass.Attributes, attribName, ref setting)) { return setting; } // Check the entire stack of modules var mod = decl.EnclosingClass.Module; while (mod != null) { if (Attributes.ContainsBool(mod.Attributes, attribName, ref setting)) { return setting; } mod = mod.Module; } return false; } /// /// Returns list of expressions if "nm" is a specified attribute: /// - if the attribute is {:nm e1,...,en}, then returns (e1,...,en) /// Otherwise, returns null. /// public static List FindExpressions(Attributes attrs, string nm) { Contract.Requires(nm != null); foreach (var attr in attrs.AsEnumerable()) { if (attr.Name == nm) { return attr.Args; } } return null; } /// /// Same as FindExpressions, but returns all matches /// public static List> FindAllExpressions(Attributes attrs, string nm) { Contract.Requires(nm != null); List> ret = null; for (; attrs != null; attrs = attrs.Prev) { if (attrs.Name == nm) { ret = ret ?? new List>(); // Avoid allocating the list in the common case where we don't find nm ret.Add(attrs.Args); } } return ret; } /// /// Returns true if "nm" is a specified attribute whose arguments match the "allowed" parameter. /// - if "nm" is not found in attrs, return false and leave value unmodified. Otherwise, /// - if "allowed" contains Empty and the Args contains zero elements, return true and leave value unmodified. Otherwise, /// - if "allowed" contains Bool and Args contains one bool literal, return true and set value to the bool literal. Otherwise, /// - if "allowed" contains Int and Args contains one BigInteger literal, return true and set value to the BigInteger literal. Otherwise, /// - if "allowed" contains String and Args contains one string literal, return true and set value to the string literal. Otherwise, /// - if "allowed" contains Expression and Args contains one element, return true and set value to the one element (of type Expression). Otherwise, /// - return false, leave value unmodified, and call reporter with an error string. /// public enum MatchingValueOption { Empty, Bool, Int, String, Expression } public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable allowed, Action reporter) { Contract.Requires(nm != null); Contract.Requires(allowed != null); Contract.Requires(reporter != null); List args = FindExpressions(attrs, nm); if (args == null) { return false; } else if (args.Count == 0) { if (allowed.Contains(MatchingValueOption.Empty)) { return true; } else { reporter("Attribute " + nm + " requires one argument"); return false; } } else if (args.Count == 1) { Expression arg = args[0]; StringLiteralExpr stringLiteral = arg as StringLiteralExpr; LiteralExpr literal = arg as LiteralExpr; if (literal != null && literal.Value is bool && allowed.Contains(MatchingValueOption.Bool)) { value = literal.Value; return true; } else if (literal != null && literal.Value is BigInteger && allowed.Contains(MatchingValueOption.Int)) { value = literal.Value; return true; } else if (stringLiteral != null && (stringLiteral.Value as string) != null && allowed.Contains(MatchingValueOption.String)) { value = stringLiteral.Value; return true; } else if (allowed.Contains(MatchingValueOption.Expression)) { value = arg; return true; } else { reporter("Attribute " + nm + " expects an argument in one of the following categories: " + String.Join(", ", allowed)); return false; } } else { reporter("Attribute " + nm + " cannot have more than one argument"); return false; } } } internal static class AttributesExtensions { public static IEnumerable AsEnumerable(this Attributes attr) { while (attr != null) { yield return attr; attr = attr.Prev; } } } // ------------------------------------------------------------------------------------------------------ public abstract class Type { public static readonly BoolType Bool = new BoolType(); public static readonly CharType Char = new CharType(); public static readonly IntType Int = new IntType(); public static readonly RealType Real = new RealType(); // Type arguments to the type public List TypeArgs = new List { }; [Pure] public abstract string TypeName(ModuleDefinition/*?*/ context); [Pure] public override string ToString() { return TypeName(null); } /// /// Return the most constrained version of "this", getting to the bottom of proxies. /// public Type Normalize() { Contract.Ensures(Contract.Result() != null); Type type = this; while (true) { var pt = type as TypeProxy; if (pt != null && pt.T != null) { type = pt.T; } else { return type; } } } /// /// Return the type that "this" stands for, getting to the bottom of proxies and following type synonyms. /// [Pure] public Type NormalizeExpand() { Contract.Ensures(Contract.Result() != null); Contract.Ensures(!(Contract.Result() is TypeProxy) || ((TypeProxy)Contract.Result()).T == null); // return a proxy only if .T == null Type type = this; while (true) { var pt = type as TypeProxy; if (pt != null && pt.T != null) { type = pt.T; continue; } var syn = type.AsTypeSynonym; if (syn != null) { var udt = (UserDefinedType)type; // correctness of cast follows from the AsTypeSynonym != null test. // Instantiate with the actual type arguments type = syn.RhsWithArgument(udt.TypeArgs); continue; } if (DafnyOptions.O.IronDafny && type is UserDefinedType) { var rc = ((UserDefinedType)type).ResolvedClass; if (rc != null) { while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { if (rc.ClonedFrom != null) { rc = (TopLevelDecl)rc.ClonedFrom; } else { Contract.Assert(rc.ExclusiveRefinement != null); rc = rc.ExclusiveRefinement; } } } if (rc is TypeSynonymDecl) { type = ((TypeSynonymDecl)rc).Rhs; continue; } } return type; } } /// /// Returns whether or not "this" and "that" denote the same type, module proxies and type synonyms. /// [Pure] public abstract bool Equals(Type that); /// /// Returns whether or not "this" and "that" could denote the same type, module proxies and type synonyms, if /// type parameters are treated as wildcards. /// public bool PossiblyEquals(Type that) { Contract.Requires(that != null); var a = NormalizeExpand(); var b = that.NormalizeExpand(); return a.AsTypeParameter != null || b.AsTypeParameter != null || a.PossiblyEquals_W(b); } /// /// Overridable worker routine for PossiblyEquals. Implementations can assume "that" to be non-null, /// and that NormalizeExpand() has been applied to both "this" and "that". Furthermore, neither "this" /// nor "that" is a TypeParameter, because that case is handled by PossiblyEquals. Recursive calls /// should go to PossiblyEquals, not directly to PossiblyEquals_W. /// public abstract bool PossiblyEquals_W(Type that); public bool IsBoolType { get { return NormalizeExpand() is BoolType; } } public bool IsCharType { get { return NormalizeExpand() is CharType; } } public bool IsIntegerType { get { return NormalizeExpand() is IntType; } } public bool IsRealType { get { return NormalizeExpand() is RealType; } } public bool IsSubrangeType { get { return NormalizeExpand() is NatType; } } public bool IsNumericBased() { var t = NormalizeExpand(); var opProxy = t as OperationTypeProxy; if (opProxy != null) { return (opProxy.AllowInts || opProxy.AllowReals) && !opProxy.AllowChar && !opProxy.AllowSeq && !opProxy.AllowSetVarieties; } return t.IsIntegerType || t.IsRealType || t.AsNewtype != null; } public enum NumericPersuation { Int, Real } [Pure] public bool IsNumericBased(NumericPersuation p) { Type t = this; while (true) { t = t.NormalizeExpand(); if (t.IsIntegerType) { return p == NumericPersuation.Int; } else if (t.IsRealType) { return p == NumericPersuation.Real; } var proxy = t as OperationTypeProxy; if (proxy != null) { if (proxy.JustInts) { return p == NumericPersuation.Int; } else if (proxy.JustReals) { return p == NumericPersuation.Real; } } var d = t.AsNewtype; if (d == null) { return false; } t = d.BaseType; } } public bool HasFinitePossibleValues { get { if (IsBoolType || IsCharType || IsRefType) { return true; } var st = AsSetType; if (st != null && st.Arg.HasFinitePossibleValues) { return true; } var mt = AsMapType; if (mt != null && mt.Domain.HasFinitePossibleValues) { return true; } var dt = AsDatatype; if (dt != null && dt.HasFinitePossibleValues) { return true; } return false; } } public CollectionType AsCollectionType { get { return NormalizeExpand() as CollectionType; } } public SetType AsSetType { get { return NormalizeExpand() as SetType; } } public MultiSetType AsMultiSetType { get { return NormalizeExpand() as MultiSetType; } } public SeqType AsSeqType { get { return NormalizeExpand() as SeqType; } } public MapType AsMapType { get { return NormalizeExpand() as MapType; } } public bool IsRefType { get { var t = NormalizeExpand(); if (t is ObjectType) { return true; } else { var udt = t as UserDefinedType; return udt != null && udt.ResolvedParam == null && udt.ResolvedClass is ClassDecl && !(udt.ResolvedClass is ArrowTypeDecl); } } } public bool IsArrayType { get { return AsArrayType != null; } } public ArrayClassDecl/*?*/ AsArrayType { get { var t = NormalizeExpand(); var udt = UserDefinedType.DenotesClass(t); return udt == null ? null : udt.ResolvedClass as ArrayClassDecl; } } public bool IsArrowType { get { return AsArrowType != null; } } public ArrowType AsArrowType { get { var t = NormalizeExpand(); return t as ArrowType; } } public bool IsIMapType { get { var t = NormalizeExpand() as MapType; return t != null && !t.Finite; } } public bool IsISetType { get { var t = NormalizeExpand() as SetType; return t != null && !t.Finite; } } public NewtypeDecl AsNewtype { get { var udt = NormalizeExpand() as UserDefinedType; return udt == null ? null : udt.ResolvedClass as NewtypeDecl; } } public TypeSynonymDecl AsTypeSynonym { get { var udt = this as UserDefinedType; // note, it is important to use 'this' here, not 'this.NormalizeExpand()' if (udt == null) { return null; } else { return udt.ResolvedClass as TypeSynonymDecl; } } } public RedirectingTypeDecl AsRedirectingType { get { var udt = this as UserDefinedType; // Note, it is important to use 'this' here, not 'this.NormalizeExpand()'. This property getter is intended to be used during resolution. if (udt == null) { return null; } else { return (RedirectingTypeDecl)(udt.ResolvedClass as TypeSynonymDecl) ?? udt.ResolvedClass as NewtypeDecl; } } } public bool IsDatatype { get { return AsDatatype != null; } } public DatatypeDecl AsDatatype { get { var udt = NormalizeExpand() as UserDefinedType; if (udt == null) { return null; } else { return udt.ResolvedClass as DatatypeDecl; } } } public bool IsIndDatatype { get { return AsIndDatatype != null; } } public IndDatatypeDecl AsIndDatatype { get { var udt = NormalizeExpand() as UserDefinedType; if (udt == null) { return null; } else { return udt.ResolvedClass as IndDatatypeDecl; } } } public bool IsCoDatatype { get { return AsCoDatatype != null; } } public CoDatatypeDecl AsCoDatatype { get { var udt = NormalizeExpand() as UserDefinedType; if (udt == null) { return null; } else { return udt.ResolvedClass as CoDatatypeDecl; } } } public bool InvolvesCoDatatype { get { return IsCoDatatype; // TODO: should really check structure of the type recursively } } public bool IsTypeParameter { get { return AsTypeParameter != null; } } public TypeParameter AsTypeParameter { get { var ct = NormalizeExpand() as UserDefinedType; return ct == null ? null : ct.ResolvedParam; } } public virtual bool SupportsEquality { get { return true; } } /// /// Returns true if it is known how to meaningfully compare the type's inhabitants. /// public bool IsOrdered { get { return !IsTypeParameter && !IsCoDatatype && !IsArrowType && !IsIMapType && !IsISetType; } } public void ForeachTypeComponent(Action action) { action(this); TypeArgs.ForEach(action); } } /// /// A NonProxy type is a fully constrained type. It may contain members. /// public abstract class NonProxyType : Type { } public abstract class BasicType : NonProxyType { public override bool PossiblyEquals_W(Type that) { return Equals(that); } } public class BoolType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "bool"; } public override bool Equals(Type that) { return that.IsBoolType; } } public class CharType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "char"; } public override bool Equals(Type that) { return that.IsCharType; } } public class IntType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "int"; } public override bool Equals(Type that) { return that.IsIntegerType; } } public class NatType : IntType { [Pure] public override string TypeName(ModuleDefinition context) { return "nat"; } } public class RealType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "real"; } public override bool Equals(Type that) { return that.IsRealType; } } public class ObjectType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "object"; } public override bool Equals(Type that) { return that.NormalizeExpand() is ObjectType; } } public class ArrowType : UserDefinedType { public List Args { get { return TypeArgs.GetRange(0, Arity); } } public Type Result { get { return TypeArgs[Arity]; } } public int Arity { get { return TypeArgs.Count - 1; } } /// /// Constructs a(n unresolved) arrow type. /// public ArrowType(IToken tok, List args, Type result) : base(tok, ArrowTypeName(args.Count), Util.Snoc(args, result)) { Contract.Requires(tok != null); Contract.Requires(args != null); Contract.Requires(result != null); } /// /// Constructs and returns a resolved arrow type. /// public ArrowType(IToken tok, List args, Type result, ModuleDefinition systemModule) : this(tok, args, result) { Contract.Requires(tok != null); Contract.Requires(args != null); Contract.Requires(result != null); Contract.Requires(systemModule != null); ResolvedClass = systemModule.TopLevelDecls.Find(d => d.Name == Name); Contract.Assume(ResolvedClass != null); } /// /// Constructs and returns a resolved arrow type. /// public ArrowType(IToken tok, ArrowTypeDecl atd, List typeArgsAndResult) : base(tok, ArrowTypeName(atd.Arity), atd, typeArgsAndResult) { Contract.Requires(tok != null); Contract.Requires(atd != null); Contract.Requires(typeArgsAndResult != null); Contract.Requires(typeArgsAndResult.Count == atd.Arity + 1); } public const string Arrow_FullCompileName = "Func"; // this is the same for all arities public override string FullCompileName { get { return Arrow_FullCompileName; } } public static string ArrowTypeName(int arity) { return "_#Func" + arity; } [Pure] public static bool IsArrowTypeName(string s) { return s.StartsWith("_#Func"); } public override string TypeName(ModuleDefinition context) { var domainNeedsParens = false; if (Arity != 1) { // 0 or 2-or-more arguments: need parentheses domainNeedsParens = true; } else { var arg = Args[0].Normalize(); // note, we do Normalize(), not NormalizeExpand(), since the TypeName will use any synonym if (arg is ArrowType) { // arrows are right associative, so we need parentheses around the domain type domainNeedsParens = true; } else { // if the domain type consists of a single tuple type, then an extra set of parentheses is needed // Note, we do NOT call .AsDatatype or .AsIndDatatype here, because those calls will do a NormalizeExpand(). Instead, we do the check manually. var udt = arg as UserDefinedType; if (udt != null && udt.ResolvedClass is TupleTypeDecl) { domainNeedsParens = true; } } } string s = ""; if (domainNeedsParens) { s += "("; } s += Util.Comma(Args, arg => arg.TypeName(context)); if (domainNeedsParens) { s += ")"; } s += " -> "; s += Result.TypeName(context); return s; } public override bool SupportsEquality { get { return false; } } } public abstract class CollectionType : NonProxyType { public abstract string CollectionTypeName { get; } public override string TypeName(ModuleDefinition context) { Contract.Ensures(Contract.Result() != null); var targs = HasTypeArg() ? "<" + Arg.TypeName(context) + ">" : ""; return CollectionTypeName + targs; } public Type Arg { get { Contract.Ensures(Contract.Result() != null); // this is true only after "arg" has really been set (i.e., it follows from the precondition) Contract.Assume(arg != null); // This is really a precondition. Don't call Arg until "arg" has been set. return arg; } } // denotes the Domain type for a Map private Type arg; // The following two methods, HasTypeArg and SetTypeArg, are to be called during resolution to make sure that "arg" becomes set. public bool HasTypeArg() { return arg != null; } public void SetTypeArg(Type arg) { Contract.Requires(arg != null); Contract.Assume(this.arg == null); // Can only set it once. This is really a precondition. this.arg = arg; this.TypeArgs = new List { arg }; } [ContractInvariantMethod] void ObjectInvariant() { // Contract.Invariant(Contract.ForAll(TypeArgs, tp => tp != null)); // After resolution, the following is invariant: Contract.Invariant(Arg != null); // However, it may not be true until then. } public CollectionType(Type arg) { this.arg = arg; this.TypeArgs = new List { arg }; } public override bool SupportsEquality { get { // Note that all collection types support equality. There is, however, a requirement (checked during resolution) // that the argument types of collections support equality. return true; } } } public class SetType : CollectionType { private bool finite; public bool Finite { get { return finite; } set { finite = value; } } public SetType(bool finite, Type arg) : base(arg) { this.finite = finite; } public override string CollectionTypeName { get { return finite ? "set" : "iset"; } } [Pure] public override bool Equals(Type that) { var t = that.NormalizeExpand() as SetType; return t != null && Finite == t.Finite && Arg.Equals(t.Arg); } public override bool PossiblyEquals_W(Type that) { var t = that as SetType; return t != null && Finite == t.Finite && Arg.PossiblyEquals(t.Arg); } } public class MultiSetType : CollectionType { public MultiSetType(Type arg) : base(arg) { } public override string CollectionTypeName { get { return "multiset"; } } public override bool Equals(Type that) { var t = that.NormalizeExpand() as MultiSetType; return t != null && Arg.Equals(t.Arg); } public override bool PossiblyEquals_W(Type that) { var t = that as MultiSetType; return t != null && Arg.PossiblyEquals(t.Arg); } } public class SeqType : CollectionType { public SeqType(Type arg) : base(arg) { } public override string CollectionTypeName { get { return "seq"; } } public override bool Equals(Type that) { var t = that.NormalizeExpand() as SeqType; return t != null && Arg.Equals(t.Arg); } public override bool PossiblyEquals_W(Type that) { var t = that as SeqType; return t != null && Arg.PossiblyEquals(t.Arg); } } public class MapType : CollectionType { public bool Finite { get { return finite; } set { finite = value; } } private bool finite; public Type Range { get { return range; } set { range = Range; TypeArgs = new List { Arg, range }; } } private Type range; public void SetRangetype(Type range) { Contract.Requires(range != null); Contract.Assume(this.range == null); // Can only set once. This is really a precondition. this.range = range; } public MapType(bool finite, Type domain, Type range) : base(domain) { Contract.Requires((domain == null && range == null) || (domain != null && range != null)); this.finite = finite; this.range = range; this.TypeArgs = new List {domain,range}; } public Type Domain { get { return Arg; } set { TypeArgs = new List { Domain, range }; } } public override string CollectionTypeName { get { return finite ? "map" : "imap"; } } [Pure] public override string TypeName(ModuleDefinition context) { Contract.Ensures(Contract.Result() != null); var targs = HasTypeArg() ? "<" + Domain.TypeName(context) + ", " + Range.TypeName(context) + ">" : ""; return CollectionTypeName + targs; } public override bool Equals(Type that) { var t = that.NormalizeExpand() as MapType; return t != null && Finite == t.Finite && Arg.Equals(t.Arg) && Range.Equals(t.Range); } public override bool PossiblyEquals_W(Type that) { var t = that as MapType; return t != null && Finite == t.Finite && Arg.PossiblyEquals(t.Arg) && Range.PossiblyEquals(t.Range); } } public class UserDefinedType : NonProxyType { [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(tok != null); Contract.Invariant(Name != null); Contract.Invariant(cce.NonNullElements(TypeArgs)); Contract.Invariant(NamePath is NameSegment || NamePath is ExprDotName); Contract.Invariant(!ArrowType.IsArrowTypeName(Name) || this is ArrowType); } public readonly Expression NamePath; // either NameSegment or ExprDotName (with the inner expression satisfying this same constraint) public readonly IToken tok; // token of the Name public readonly string Name; [Rep] public string FullName { get { if (ResolvedClass != null && !ResolvedClass.Module.IsDefaultModule) { return ResolvedClass.Module.Name + "." + Name; } else { return Name; } } } string compileName; string CompileName { get { if (compileName == null) { compileName = NonglobalVariable.CompilerizeName(Name); } return compileName; } } public virtual string FullCompileName { get { if (ResolvedClass != null && !ResolvedClass.Module.IsDefaultModule) { return ResolvedClass.Module.CompileName + ".@" + ResolvedClass.CompileName; } else { return CompileName; } } } public string FullCompanionCompileName { get { Contract.Requires(ResolvedClass is TraitDecl); var m = ResolvedClass.Module; while (DafnyOptions.O.IronDafny && m.ClonedFrom != null) { m = m.ClonedFrom; } var s = m.IsDefaultModule ? "" : m.CompileName + "."; return s + "@_Companion_" + CompileName; } } public TopLevelDecl ResolvedClass; // filled in by resolution, if Name denotes a class/datatype/iterator and TypeArgs match the type parameters of that class/datatype/iterator public TypeParameter ResolvedParam; // filled in by resolution, if Name denotes an enclosing type parameter and TypeArgs is the empty list public UserDefinedType(IToken tok, string name, List optTypeArgs) : this(tok, new NameSegment(tok, name, optTypeArgs)) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(optTypeArgs == null || optTypeArgs.Count > 0); // this is what it means to be syntactically optional } public UserDefinedType(IToken tok, Expression namePath) { Contract.Requires(tok != null); Contract.Requires(namePath is NameSegment || namePath is ExprDotName); this.tok = tok; if (namePath is NameSegment) { var n = (NameSegment)namePath; this.Name = n.Name; this.TypeArgs = n.OptTypeArguments; } else { var n = (ExprDotName)namePath; this.Name = n.SuffixName; this.TypeArgs = n.OptTypeArguments; } if (this.TypeArgs == null) { this.TypeArgs = new List(); // TODO: is this really the thing to do? } this.NamePath = namePath; } /// /// Constructs a Type (in particular, a UserDefinedType) from a TopLevelDecl denoting a type declaration. If /// the given declaration takes type parameters, these are filled as references to the formal type parameters /// themselves. (Usually, this method is called when the type parameters in the result don't matter, other /// than that they need to be filled in, so as to make a properly resolved UserDefinedType.) /// public static UserDefinedType FromTopLevelDecl(IToken tok, TopLevelDecl cd) { Contract.Requires(tok != null); Contract.Requires(cd != null); Contract.Assert((cd is ArrowTypeDecl) == ArrowType.IsArrowTypeName(cd.Name)); var args = cd.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp)); if (cd is ArrowTypeDecl) { return new ArrowType(tok, (ArrowTypeDecl)cd, args); } else { return new UserDefinedType(tok, cd.Name, cd, args); } } /// /// This constructor constructs a resolved class/datatype/iterator type /// public UserDefinedType(IToken tok, string name, TopLevelDecl cd, [Captured] List typeArgs) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cd != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cd.TypeArgs.Count == typeArgs.Count); this.tok = tok; this.Name = name; this.ResolvedClass = cd; this.TypeArgs = typeArgs; var ns = new NameSegment(tok, name, typeArgs.Count == 0 ? null : typeArgs); var r = new Resolver_IdentifierExpr(tok, cd, typeArgs); ns.ResolvedExpression = r; ns.Type = r.Type; this.NamePath = ns; } /// /// This constructor constructs a resolved type parameter /// public UserDefinedType(TypeParameter tp) : this(tp.tok, tp) { Contract.Requires(tp != null); } /// /// This constructor constructs a resolved type parameter /// public UserDefinedType(IToken tok, TypeParameter tp) { Contract.Requires(tok != null); Contract.Requires(tp != null); this.tok = tok; this.Name = tp.Name; this.TypeArgs = new List(); this.ResolvedParam = tp; var ns = new NameSegment(tok, tp.Name, null); var r = new Resolver_IdentifierExpr(tok, tp); ns.ResolvedExpression = r; ns.Type = r.Type; this.NamePath = ns; } public override bool Equals(Type that) { var i = NormalizeExpand(); if (i is UserDefinedType) { var ii = (UserDefinedType)i; var t = that.NormalizeExpand() as UserDefinedType; if (ii.ResolvedParam != null) { return t != null && t.ResolvedParam == ii.ResolvedParam; } else if (t == null || ii.ResolvedClass != t.ResolvedClass || ii.TypeArgs.Count != t.TypeArgs.Count) { return false; } else { for (int j = 0; j < ii.TypeArgs.Count; j++) { if (!ii.TypeArgs[j].Equals(t.TypeArgs[j])) { return false; } } return true; } } else { return i.Equals(that); } } public override bool PossiblyEquals_W(Type that) { Contract.Assume(ResolvedParam == null); // we get this assumption from the caller, PossiblyEquals var t = that as UserDefinedType; if (t != null && ResolvedClass != null && ResolvedClass == t.ResolvedClass) { for (int j = 0; j < TypeArgs.Count; j++) { if (!TypeArgs[j].PossiblyEquals(t.TypeArgs[j])) { return false; } } return true; } return false; } /// /// If type denotes a resolved class type, then return that class type. /// Otherwise, return null. /// public static UserDefinedType DenotesClass(Type type) { Contract.Requires(type != null); Contract.Ensures(Contract.Result() == null || Contract.Result().ResolvedClass is ClassDecl); type = type.NormalizeExpand(); UserDefinedType ct = type as UserDefinedType; if (ct != null && ct.ResolvedClass is ClassDecl) { return ct; } else { return null; } } public static Type ArrayElementType(Type type) { Contract.Requires(type.IsArrayType); Contract.Requires(type != null); Contract.Ensures(Contract.Result() != null); UserDefinedType udt = DenotesClass(type); Contract.Assert(udt != null); Contract.Assert(udt.TypeArgs.Count == 1); // holds true of all array types return udt.TypeArgs[0]; } [Pure] public override string TypeName(ModuleDefinition context) { Contract.Ensures(Contract.Result() != null); if (BuiltIns.IsTupleTypeName(Name)) { return "(" + Util.Comma(",", TypeArgs, ty => ty.TypeName(context)) + ")"; } else { #if TEST_TYPE_SYNONYM_TRANSPARENCY if (Name == "type#synonym#transparency#test" && ResolvedClass is TypeSynonymDecl) { return ((TypeSynonymDecl)ResolvedClass).Rhs.TypeName(context); } #endif var s = Printer.ExprToString(NamePath); if (ResolvedClass != null) { var optionalTypeArgs = NamePath is NameSegment ? ((NameSegment)NamePath).OptTypeArguments : ((ExprDotName)NamePath).OptTypeArguments; if (optionalTypeArgs == null && TypeArgs != null && TypeArgs.Count != 0) { s += "<" + Util.Comma(",", TypeArgs, ty => ty.TypeName(context)) + ">"; } } return s; } } public override bool SupportsEquality { get { if (ResolvedClass is ClassDecl || ResolvedClass is NewtypeDecl) { return true; } else if (ResolvedClass is CoDatatypeDecl) { return false; } else if (ResolvedClass is IndDatatypeDecl) { var dt = (IndDatatypeDecl)ResolvedClass; Contract.Assume(dt.EqualitySupport != IndDatatypeDecl.ES.NotYetComputed); if (dt.EqualitySupport == IndDatatypeDecl.ES.Never) { return false; } Contract.Assert(dt.TypeArgs.Count == TypeArgs.Count); var i = 0; foreach (var tp in dt.TypeArgs) { if (tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype && !TypeArgs[i].SupportsEquality) { return false; } i++; } return true; } else if (ResolvedClass is TypeSynonymDecl) { var t = (TypeSynonymDecl)ResolvedClass; return t.RhsWithArgument(TypeArgs).SupportsEquality; } else if (ResolvedParam != null) { return ResolvedParam.MustSupportEquality; } Contract.Assume(false); // the SupportsEquality getter requires the Type to have been successfully resolved return true; } } } public abstract class TypeProxy : Type { public Type T; // filled in during resolution internal TypeProxy() { } [Pure] public override string TypeName(ModuleDefinition context) { Contract.Ensures(Contract.Result() != null); return T == null ? "?" : T.TypeName(context); } public override bool SupportsEquality { get { if (T != null) { return T.SupportsEquality; } else { return base.SupportsEquality; } } } public override bool Equals(Type that) { var i = NormalizeExpand(); if (i is TypeProxy) { var u = that.NormalizeExpand() as TypeProxy; return u != null && object.ReferenceEquals(i, u); } else { return i.Equals(that); } } public override bool PossiblyEquals_W(Type that) { return false; // we don't consider unresolved proxies as worthy of "possibly equals" status } } public abstract class UnrestrictedTypeProxy : TypeProxy { } /// /// This proxy stands for any type. /// public class InferredTypeProxy : UnrestrictedTypeProxy { } /// /// This proxy stands for any type, but it originates from an instantiated type parameter. /// public class ParamTypeProxy : UnrestrictedTypeProxy { public TypeParameter orig; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(orig != null); } public ParamTypeProxy(TypeParameter orig) { Contract.Requires(orig != null); this.orig = orig; } } public abstract class RestrictedTypeProxy : TypeProxy { /// /// The OrderID is used to simplify the unification code. Each restricted type proxy should use its /// own OrderID. /// public abstract int OrderID { get; } } /// /// This proxy stands for any datatype. /// public class DatatypeProxy : RestrictedTypeProxy { public readonly bool Co; // false means only inductive datatypes; true means only co-inductive datatypes public readonly bool TypeVariableOK; public DatatypeProxy(bool co, bool typeVariableOk = false) { Co = co; TypeVariableOK = typeVariableOk; } public override int OrderID { get { return 0; } } } /// /// This proxy stands for object or any class/array type. /// public class ObjectTypeProxy : RestrictedTypeProxy { public override int OrderID { get { return 1; } } } /// /// This proxy stands for: /// set(Arg) or iset(Arg) or multiset(Arg) or seq(Arg) or map(Arg, anyRange) or imap(Arg, anyRange) /// public class CollectionTypeProxy : RestrictedTypeProxy { public readonly Type Arg; public readonly bool AllowIMap; public readonly bool AllowISet; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Arg != null); } public CollectionTypeProxy(Type arg, bool allowIMap, bool allowISet) { Contract.Requires(arg != null); Arg = arg; AllowIMap = allowIMap; AllowISet = allowISet; } public override int OrderID { get { return 2; } } } /// /// This proxy can stand for any numeric type. /// In addition, if AllowSeq, then it can stand for a seq. /// In addition, if AllowSetVarieties, it can stand for a set or multiset. /// In addition, if AllowISet, then it can stand for a iset /// public class OperationTypeProxy : RestrictedTypeProxy { public readonly bool AllowInts; public readonly bool AllowReals; public readonly bool AllowChar; public readonly bool AllowSeq; public readonly bool AllowSetVarieties; public readonly bool AllowISet; public bool JustInts { get { return AllowInts && !AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties && !AllowISet; } } public bool JustReals { get { return !AllowInts && AllowReals && !AllowChar && !AllowSeq && !AllowSetVarieties && !AllowISet; } } public OperationTypeProxy(bool allowInts, bool allowReals, bool allowChar, bool allowSeq, bool allowSetVarieties, bool allowISet) { Contract.Requires(allowInts || allowReals || allowChar || allowSeq || allowSetVarieties); // don't allow unsatisfiable constraint Contract.Requires(!(!allowInts && !allowReals && allowChar && !allowSeq && !allowSetVarieties)); // to constrain to just char, don't use a proxy AllowInts = allowInts; AllowReals = allowReals; AllowChar = allowChar; AllowSeq = allowSeq; AllowSetVarieties = allowSetVarieties; AllowISet = allowISet; } public override int OrderID { get { return 3; } } [Pure] public override string TypeName(ModuleDefinition context) { Contract.Ensures(Contract.Result() != null); if (T == null) { if (JustInts) { return "int"; } else if (JustReals) { return "real"; } } return base.TypeName(context); } } /// /// Domain and Range refer to the types of the indexing operation. That is, in A[i], /// i is of type Domain and A[i] is of type Range. /// Arg is either Domain or Range, depending on what type it is. Arg is the type /// one would use in an expression "x in C", whereas /// This proxy stands for one of: /// seq(T) Domain,Range,Arg := integer,T,T /// multiset(T) Domain,Range,Arg := T,integer,T /// if AllowMap, may also be: /// map(T,U) Domain,Range,Arg := T,U,T /// if AllowArray, may also be: /// array(T) Domain,Range,Arg := integer,T,T /// where "integer" refers to any integer-based numeric type. /// public class IndexableTypeProxy : RestrictedTypeProxy { public readonly bool AllowMap; public readonly bool AllowIMap; public readonly bool AllowArray; public readonly Type Domain, Range, Arg; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Domain != null); Contract.Invariant(Range != null); Contract.Invariant(Arg != null); } public IndexableTypeProxy(Type domain, Type range, Type arg, bool allowMap, bool allowIMap, bool allowArray) { Contract.Requires(domain != null); Contract.Requires(range != null); Contract.Requires(arg != null); Domain = domain; Range = range; Arg = arg; AllowMap = allowMap; AllowIMap = allowIMap; AllowArray = allowArray; } public override int OrderID { get { return 4; } } } // ------------------------------------------------------------------------------------------------------ /// /// This interface is used by the Dafny IDE. /// public interface INamedRegion { IToken BodyStartTok { get; } IToken BodyEndTok { get; } string Name { get; } } public abstract class Declaration : INamedRegion { [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(tok != null); Contract.Invariant(Name != null); } public IToken tok; public IToken BodyStartTok = Token.NoToken; public IToken BodyEndTok = Token.NoToken; public readonly string Name; IToken INamedRegion.BodyStartTok { get { return BodyStartTok; } } IToken INamedRegion.BodyEndTok { get { return BodyEndTok; } } string INamedRegion.Name { get { return Name; } } string compileName; private readonly Declaration clonedFrom; public virtual string CompileName { get { if (compileName == null) { object externValue = ""; string errorMessage = ""; bool isExternal = Attributes.ContainsMatchingValue(this.Attributes, "extern", ref externValue, new Attributes.MatchingValueOption[] { Attributes.MatchingValueOption.String }, err => errorMessage = err); if (isExternal) { compileName = (string)externValue; } else { compileName = NonglobalVariable.CompilerizeName(Name); } } return compileName; } } public Attributes Attributes; // readonly, except during class merging in the refinement transformations public Declaration(IToken tok, string name, Attributes attributes, Declaration clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); this.tok = tok; this.Name = name; this.Attributes = attributes; this.clonedFrom = clonedFrom; } public Declaration ClonedFrom { get { return this.clonedFrom; } } [Pure] public override string ToString() { Contract.Ensures(Contract.Result() != null); return Name; } internal FreshIdGenerator IdGenerator = new FreshIdGenerator(); } public class OpaqueType_AsParameter : TypeParameter { public readonly List TypeArgs; public OpaqueType_AsParameter(IToken tok, string name, EqualitySupportValue equalitySupport, List typeArgs) : base(tok, name, equalitySupport) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(typeArgs != null); TypeArgs = typeArgs; } } public class TypeParameter : Declaration { public interface ParentType { string FullName { get; } } [Peer] ParentType parent; public ParentType Parent { get { return parent; } [param: Captured] set { Contract.Requires(Parent == null); // set it only once Contract.Requires(value != null); parent = value; } } public enum EqualitySupportValue { Required, InferredRequired, Unspecified } public EqualitySupportValue EqualitySupport; // the resolver may change this value from Unspecified to InferredRequired (for some signatures that may immediately imply that equality support is required) public bool MustSupportEquality { get { return EqualitySupport != EqualitySupportValue.Unspecified; } } public bool NecessaryForEqualitySupportOfSurroundingInductiveDatatype = false; // computed during resolution; relevant only when Parent denotes an IndDatatypeDecl public bool IsAbstractTypeDeclaration { // true if this type parameter represents t in type t; get { return parent == null; } } public bool IsToplevelScope { // true if this type parameter is on a toplevel (ie. class C), and false if it is on a member (ie. method m(...)) get { return parent is TopLevelDecl; } } public int PositionalIndex; // which type parameter this is (ie. in C, S is 0, T is 1 and U is 2). public TypeParameter(IToken tok, string name, EqualitySupportValue equalitySupport = EqualitySupportValue.Unspecified, Declaration clonedFrom = null) : base(tok, name, null, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); EqualitySupport = equalitySupport; } public TypeParameter(IToken tok, string name, int positionalIndex, ParentType parent) : this(tok, name) { PositionalIndex = positionalIndex; Parent = parent; } public string FullName() { // when debugging, print it all: return /* Parent.FullName + "." + */ Name; } } // Represents a submodule declaration at module level scope abstract public class ModuleDecl : TopLevelDecl { public override string WhatKind { get { return "module"; } } public ModuleSignature Signature; // filled in by resolution, in topological order. public int Height; public readonly bool Opened; public ModuleDecl(IToken tok, string name, ModuleDefinition parent, bool opened) : base(tok, name, parent, new List(), null) { Height = -1; Signature = null; Opened = opened; } public abstract object Dereference(); } // Represents module X { ... } public class LiteralModuleDecl : ModuleDecl { public readonly ModuleDefinition ModuleDef; public ModuleSignature DefaultExport; // the default export of the module. fill in by the resolver. public LiteralModuleDecl(ModuleDefinition module, ModuleDefinition parent) : base(module.tok, module.Name, parent, false) { ModuleDef = module; } public override object Dereference() { return ModuleDef; } } // Represents "module name = path;", where name is an identifier and path is a possibly qualified name. public class AliasModuleDecl : ModuleDecl { public readonly List Path; // generated by the parser, this is looked up public ModuleDecl Root; // the moduleDecl that Path[0] refers to. public AliasModuleDecl(List path, IToken name, ModuleDefinition parent, bool opened) : base(name, name.val, parent, opened) { Contract.Requires(path != null && path.Count > 0); Path = path; } public override object Dereference() { return Signature.ModuleDef; } } // Represents "module name as path [ = compilePath];", where name is a identifier and path is a possibly qualified name. public class ModuleFacadeDecl : ModuleDecl { public ModuleDecl Root; public readonly List Path; public ModuleDecl CompileRoot; public readonly List CompilePath; public ModuleSignature OriginalSignature; public ModuleFacadeDecl(List path, IToken name, ModuleDefinition parent, List compilePath, bool opened) : base(name, name.val, parent, opened) { Path = path; Root = null; CompilePath = compilePath; } public override object Dereference() { return this; } } // Represents the exports of a module. public class ModuleExportDecl : ModuleDecl { public bool IsDefault; public List Exports; // list of TopLevelDecl that are included in the export public List Extends; // list of exports that are extended public readonly List ExtendDecls = new List(); // fill in by the resolver public ModuleExportDecl(IToken tok, ModuleDefinition parent, bool isDefault, List exports, List extends) : base(tok, tok.val, parent, false) { IsDefault = isDefault; Exports = exports; Extends = extends; } public override object Dereference() { return this; } } public class ExportSignature { public bool IncludeBody; public IToken Id; public string Name; public Declaration Decl; // fill in by the resolver public ExportSignature(IToken id, bool includeBody) { Id = id; Name = id.val; IncludeBody = includeBody; } } public class ModuleSignature { private ModuleDefinition exclusiveRefinement = null; public readonly Dictionary TopLevels = new Dictionary(); public readonly Dictionary> Ctors = new Dictionary>(); public readonly Dictionary StaticMembers = new Dictionary(); public ModuleDefinition ModuleDef = null; // Note: this is null if this signature does not correspond to a specific definition (i.e. // it is abstract). Otherwise, it points to that definition. public ModuleSignature CompileSignature = null; // This is the version of the signature that should be used at compile time. public ModuleSignature Refines = null; public bool IsAbstract = false; public ModuleSignature() {} public bool FindSubmodule(string name, out ModuleSignature pp) { TopLevelDecl top; if (TopLevels.TryGetValue(name, out top) && top is ModuleDecl) { pp = ((ModuleDecl)top).Signature; return true; } else { pp = null; return false; } } public ModuleDefinition ExclusiveRefinement { get { if (null == exclusiveRefinement) { return ModuleDef == null ? null : ModuleDef.ExclusiveRefinement; } else { return exclusiveRefinement; } } set { if (null == ExclusiveRefinement) { exclusiveRefinement = null; } else { throw new InvalidOperationException("An exclusive refinement relationship cannot be amended."); } } } } public class ModuleDefinition : INamedRegion { public readonly IToken tok; public IToken BodyStartTok = Token.NoToken; public IToken BodyEndTok = Token.NoToken; public readonly string Name; IToken INamedRegion.BodyStartTok { get { return BodyStartTok; } } IToken INamedRegion.BodyEndTok { get { return BodyEndTok; } } string INamedRegion.Name { get { return Name; } } public readonly ModuleDefinition Module; public readonly Attributes Attributes; public readonly List RefinementBaseName; // null if no refinement base public ModuleDecl RefinementBaseRoot; // filled in early during resolution, corresponds to RefinementBaseName[0] public List Includes; public readonly List TopLevelDecls = new List(); // filled in by the parser; readonly after that public readonly Graph CallGraph = new Graph(); // filled in during resolution public int Height; // height in the topological sorting of modules; filled in during resolution public readonly bool IsAbstract; public readonly bool IsExclusiveRefinement; public readonly bool IsFacade; // True iff this module represents a module facade (that is, an abstract interface) private readonly bool IsBuiltinName; // true if this is something like _System that shouldn't have it's name mangled. private ModuleDefinition exclusiveRefinement; public ModuleDefinition ExclusiveRefinement { get { return exclusiveRefinement; } set { if (null == exclusiveRefinement) { if (!value.IsExclusiveRefinement) { throw new ArgumentException( string.Format("Exclusive refinement of {0} with 'new' module {0} is disallowed.", Name, value.Name)); } // todo: validate state of `value`. exclusiveRefinement = value; } else { throw new InvalidOperationException(string.Format("Exclusive refinement of {0} has already been established {1}; cannot reestabilish as {2}.", Name, exclusiveRefinement.Name, value.Name)); } } } public int ExclusiveRefinementCount { get; set; } private ModuleSignature refinementBaseSig; // module signature of the refinementBase. public ModuleSignature RefinementBaseSig { get { return refinementBaseSig; } set { // the refinementBase member may only be changed once. if (null != refinementBaseSig) { throw new InvalidOperationException(string.Format("This module ({0}) already has a refinement base ({1}).", Name, refinementBase.Name)); } refinementBaseSig = value; } } private ModuleDefinition refinementBase; // filled in during resolution via RefinementBase property (null if no refinement base yet or at all). public ModuleDefinition RefinementBase { get { return refinementBase; } set { // the refinementBase member may only be changed once. if (null != refinementBase) { throw new InvalidOperationException(string.Format("This module ({0}) already has a refinement base ({1}).", Name, refinementBase.Name)); } refinementBase = value; } } public ModuleDefinition ClonedFrom { get; set; } [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(TopLevelDecls)); Contract.Invariant(CallGraph != null); } public ModuleDefinition(IToken tok, string name, bool isAbstract, bool isFacade, bool isExclusiveRefinement, List refinementBase, ModuleDefinition parent, Attributes attributes, bool isBuiltinName, Parser parser = null) { Contract.Requires(tok != null); Contract.Requires(name != null); this.tok = tok; this.Name = name; this.Attributes = attributes; this.Module = parent; RefinementBaseName = refinementBase; IsAbstract = isAbstract; IsFacade = isFacade; IsExclusiveRefinement = isExclusiveRefinement; RefinementBaseRoot = null; this.refinementBase = null; Includes = new List(); IsBuiltinName = isBuiltinName; if (isExclusiveRefinement && !DafnyOptions.O.IronDafny) { parser.errors.SynErr( tok.filename, tok.line, tok.col, "The exclusively keyword is experimental and only available when IronDafny features are enabled (/ironDafny)."); } } public virtual bool IsDefaultModule { get { return false; } } string compileName; public string CompileName { get { if (compileName == null) { object externValue = ""; string errorMessage = ""; bool isExternal = Attributes.ContainsMatchingValue(this.Attributes, "extern", ref externValue, new Attributes.MatchingValueOption[] { Attributes.MatchingValueOption.String }, err => errorMessage = err); if (isExternal) { compileName = (string)externValue; } else { if (IsBuiltinName) compileName = Name; else compileName = "_" + Height.ToString() + "_" + NonglobalVariable.CompilerizeName(Name); } } return compileName; } } public string RefinementCompileName { get { if (ExclusiveRefinement != null) { return this.ExclusiveRefinement.RefinementCompileName; } else { return this.CompileName; } } } /// /// Determines if "a" and "b" are in the same strongly connected component of the call graph, that is, /// if "a" and "b" are mutually recursive. /// Assumes that CallGraph has already been filled in for the modules containing "a" and "b". /// public static bool InSameSCC(ICallable a, ICallable b) { Contract.Requires(a != null); Contract.Requires(b != null); var module = a.EnclosingModule; return module == b.EnclosingModule && module.CallGraph.GetSCCRepresentative(a) == module.CallGraph.GetSCCRepresentative(b); } /// /// Return the representative elements of the SCCs that contain contain any member declaration in a /// class in "declarations". /// Note, the representative element may in some cases be a Method, not necessarily a Function. /// public static IEnumerable AllFunctionSCCs(List declarations) { var set = new HashSet(); foreach (var d in declarations) { var cl = d as ClassDecl; if (cl != null) { var module = cl.Module; foreach (var member in cl.Members) { var fn = member as Function; if (fn != null) { var repr = module.CallGraph.GetSCCRepresentative(fn); set.Add(repr); } } } } return set; } public static IEnumerable AllFunctions(List declarations) { foreach (var d in declarations) { var cl = d as ClassDecl; if (cl != null) { foreach (var member in cl.Members) { var fn = member as Function; if (fn != null) { yield return fn; } } } } } /// /// Yields all functions and methods that are members of some class in the given list of /// declarations. /// Note, an iterator declaration is a class, in this sense. /// Note, if the given list are the top-level declarations of a module, the yield will include /// colemmas but not their associated prefix lemmas (which are tucked into the colemma's /// .PrefixLemma field). /// public static IEnumerable AllCallables(List declarations) { foreach (var d in declarations) { var cl = d as ClassDecl; if (cl != null) { foreach (var member in cl.Members) { var clbl = member as ICallable; if (clbl != null) { yield return clbl; } } } } } /// /// Yields all functions and methods that are members of some non-iterator class in the given /// list of declarations, as well as any IteratorDecl's in that list. /// public static IEnumerable AllItersAndCallables(List declarations) { foreach (var d in declarations) { if (d is IteratorDecl) { var iter = (IteratorDecl)d; yield return iter; } else if (d is ClassDecl) { var cl = (ClassDecl)d; foreach (var member in cl.Members) { var clbl = member as ICallable; if (clbl != null) { yield return clbl; } } } } } public static IEnumerable AllIteratorDecls(List declarations) { foreach (var d in declarations) { var iter = d as IteratorDecl; if (iter != null) { yield return iter; } } } public static IEnumerable AllFixpointLemmas(List declarations) { foreach (var d in declarations) { var cl = d as ClassDecl; if (cl != null) { foreach (var member in cl.Members) { var m = member as FixpointLemma; if (m != null) { yield return m; } } } } } } public class DefaultModuleDecl : ModuleDefinition { public DefaultModuleDecl() : base(Token.NoToken, "_module", false, false, /*isExclusiveRefinement:*/ false, null, null, null, true) { } public override bool IsDefaultModule { get { return true; } } } public abstract class TopLevelDecl : Declaration, TypeParameter.ParentType { public abstract string WhatKind { get; } public readonly ModuleDefinition Module; public readonly List TypeArgs; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(TypeArgs)); } public TopLevelDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, Attributes attributes, Declaration clonedFrom = null) : base(tok, name, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Module = module; TypeArgs = typeArgs; ExclusiveRefinement = null; } public string FullName { get { return Module.Name + "." + Name; } } public string FullSanitizedName { get { return Module.CompileName + "." + CompileName; } } public string FullSanitizedRefinementName { get { return Module.RefinementCompileName + "." + CompileName; } } public string FullNameInContext(ModuleDefinition context) { if (Module == context) { return Name; } else { return Module.Name + "." + Name; } } public string FullCompileName { get { if (!Module.IsDefaultModule) { return Module.CompileName + ".@" + CompileName; } else { return CompileName; } } } public TopLevelDecl ExclusiveRefinement { get; set; } } public class TraitDecl : ClassDecl { public override string WhatKind { get { return "trait"; } } public bool IsParent { set; get; } public TraitDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, [Captured] List members, Attributes attributes, TraitDecl clonedFrom = null) : base(tok, name, module, typeArgs, members, attributes, null, clonedFrom) { } } public class ClassDecl : TopLevelDecl { public override string WhatKind { get { return "class"; } } public readonly List Members; public readonly List InheritedMembers = new List(); // these are non-ghost instance fields and instance members defined with bodies in traits (this list is used by the compiler) public readonly List TraitsTyp; // these are the types that are parsed after the keyword 'extends' public readonly List TraitsObj = new List(); // populated during resolution public bool HasConstructor; // filled in (early) during resolution; true iff there exists a member that is a Constructor [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(Members)); Contract.Invariant(TraitsTyp != null); Contract.Invariant(TraitsObj != null); } public ClassDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, [Captured] List members, Attributes attributes, List traits, ClassDecl clonedFrom = null) : base(tok, name, module, typeArgs, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(members)); Members = members; TraitsTyp = traits ?? new List(); } public virtual bool IsDefaultClass { get { return false; } } public new ClassDecl ClonedFrom { get { return (ClassDecl)base.ClonedFrom; } } } public class DefaultClassDecl : ClassDecl { public DefaultClassDecl(ModuleDefinition module, [Captured] List members, DefaultClassDecl clonedFrom = null) : base(Token.NoToken, "_default", module, new List(), members, null, null, clonedFrom) { Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(members)); } public override bool IsDefaultClass { get { return true; } } } public class ArrayClassDecl : ClassDecl { public override string WhatKind { get { return "array type"; } } public readonly int Dims; public ArrayClassDecl(int dims, ModuleDefinition module, Attributes attrs) : base(Token.NoToken, BuiltIns.ArrayClassName(dims), module, new List(new TypeParameter[]{new TypeParameter(Token.NoToken, "arg")}), new List(), attrs, null) { Contract.Requires(1 <= dims); Contract.Requires(module != null); Dims = dims; } } public class ArrowTypeDecl : ClassDecl { public override string WhatKind { get { return "function type"; } } public readonly int Arity; public readonly Function Requires; public readonly Function Reads; public ArrowTypeDecl(List tps, Function req, Function reads, ModuleDefinition module, Attributes attributes, ArrowTypeDecl clonedFrom) : base(Token.NoToken, ArrowType.ArrowTypeName(tps.Count - 1), module, tps, new List { req, reads }, attributes, null, clonedFrom) { Contract.Requires(tps != null && 1 <= tps.Count); Contract.Requires(req != null); Contract.Requires(reads != null); Contract.Requires(module != null); Arity = tps.Count - 1; Requires = req; Reads = reads; Requires.EnclosingClass = this; Reads.EnclosingClass = this; } } public abstract class DatatypeDecl : TopLevelDecl { public readonly List Ctors; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(Ctors)); Contract.Invariant(1 <= Ctors.Count); } public DatatypeDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, [Captured] List ctors, Attributes attributes, DatatypeDecl clonedFrom = null) : base(tok, name, module, typeArgs, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ctors)); Contract.Requires(1 <= ctors.Count); Ctors = ctors; } public bool HasFinitePossibleValues { get { return (TypeArgs.Count == 0 && Ctors.TrueForAll(ctr => ctr.Formals.Count == 0)); } } public new DatatypeDecl ClonedFrom { get { return (DatatypeDecl)base.ClonedFrom; } } } public class IndDatatypeDecl : DatatypeDecl { public override string WhatKind { get { return "datatype"; } } public DatatypeCtor DefaultCtor; // set during resolution public bool[] TypeParametersUsedInConstructionByDefaultCtor; // set during resolution; has same length as the number of type arguments public enum ES { NotYetComputed, Never, ConsultTypeArguments } public ES EqualitySupport = ES.NotYetComputed; public IndDatatypeDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, [Captured] List ctors, Attributes attributes, IndDatatypeDecl clonedFrom = null) : base(tok, name, module, typeArgs, ctors, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ctors)); Contract.Requires(1 <= ctors.Count); } public new IndDatatypeDecl ClonedFrom { get { return (IndDatatypeDecl)base.ClonedFrom; } } } public class TupleTypeDecl : IndDatatypeDecl { public readonly int Dims; /// /// Construct a resolved built-in tuple type with "dim" arguments. "systemModule" is expected to be the _System module. /// public TupleTypeDecl(int dims, ModuleDefinition systemModule) : this(systemModule, CreateTypeParameters(dims)) { Contract.Requires(0 <= dims); Contract.Requires(systemModule != null); } private TupleTypeDecl(ModuleDefinition systemModule, List typeArgs) : base(Token.NoToken, BuiltIns.TupleTypeName(typeArgs.Count), systemModule, typeArgs, CreateConstructors(typeArgs), null) { Contract.Requires(systemModule != null); Contract.Requires(typeArgs != null); Dims = typeArgs.Count; foreach (var ctor in Ctors) { ctor.EnclosingDatatype = this; // resolve here DefaultCtor = ctor; TypeParametersUsedInConstructionByDefaultCtor = new bool[typeArgs.Count]; for (int i = 0; i < typeArgs.Count; i++) { TypeParametersUsedInConstructionByDefaultCtor[i] = true; } } this.EqualitySupport = ES.ConsultTypeArguments; } private static List CreateTypeParameters(int dims) { Contract.Requires(0 <= dims); var ts = new List(); for (int i = 0; i < dims; i++) { ts.Add(new TypeParameter(Token.NoToken, "T" + i)); } return ts; } private static List CreateConstructors(List typeArgs) { Contract.Requires(typeArgs != null); var formals = new List(); for (int i = 0; i < typeArgs.Count; i++) { var tp = typeArgs[i]; var f = new Formal(Token.NoToken, i.ToString(), new UserDefinedType(Token.NoToken, tp), true, false); formals.Add(f); } var ctor = new DatatypeCtor(Token.NoToken, BuiltIns.TupleTypeCtorName, formals, null); return new List() { ctor }; } } public class CoDatatypeDecl : DatatypeDecl { public override string WhatKind { get { return "codatatype"; } } public CoDatatypeDecl SscRepr; // filled in during resolution public CoDatatypeDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, [Captured] List ctors, Attributes attributes, CoDatatypeDecl clonedFrom = null) : base(tok, name, module, typeArgs, ctors, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ctors)); Contract.Requires(1 <= ctors.Count); } } public class DatatypeCtor : Declaration, TypeParameter.ParentType { public readonly List Formals; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(Formals)); Contract.Invariant(Destructors != null); Contract.Invariant( Destructors.Count == 0 || // this is until resolution Destructors.Count == Formals.Count); // after resolution } // TODO: One could imagine having a precondition on datatype constructors public DatatypeDecl EnclosingDatatype; // filled in during resolution public SpecialField QueryField; // filled in during resolution public List Destructors = new List(); // contents filled in during resolution; includes both implicit (not mentionable in source) and explicit destructors public DatatypeCtor(IToken tok, string name, [Captured] List formals, Attributes attributes, DatatypeCtor clonedFrom = null) : base(tok, name, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(formals)); this.Formals = formals; } public string FullName { get { Contract.Ensures(Contract.Result() != null); Contract.Assume(EnclosingDatatype != null); return "#" + EnclosingDatatype.FullName + "." + Name; } } } /// /// An ICodeContext is an ICallable or a NoContext. /// public interface ICodeContext { bool IsGhost { get; } List TypeArgs { get; } List Ins { get ; } ModuleDefinition EnclosingModule { get; } // to be called only after signature-resolution is complete bool MustReverify { get; } string FullSanitizedName { get; } bool AllowsNontermination { get; } bool ContainsQuantifier { get; set; } } /// /// An ICallable is a Function, Method, IteratorDecl, or RedirectingTypeDecl. /// public interface ICallable : ICodeContext { IToken Tok { get; } string WhatKind { get; } string NameRelativeToModule { get; } Specification Decreases { get; } /// /// The InferredDecreases property says whether or not a process was attempted to provide a default decreases /// clause. If such a process was attempted, even if the resulting decreases clause turned out to be empty, /// the property will get the value "true". This is so that a useful error message can be provided. /// bool InferredDecreases { get; set; } } public class DontUseICallable : ICallable { public string WhatKind { get { throw new cce.UnreachableException(); } } public bool IsGhost { get { throw new cce.UnreachableException(); } } public List TypeArgs { get { throw new cce.UnreachableException(); } } public List Ins { get { throw new cce.UnreachableException(); } } public ModuleDefinition EnclosingModule { get { throw new cce.UnreachableException(); } } public bool MustReverify { get { throw new cce.UnreachableException(); } } public string FullSanitizedName { get { throw new cce.UnreachableException(); } } public bool AllowsNontermination { get { throw new cce.UnreachableException(); } } public IToken Tok { get { throw new cce.UnreachableException(); } } public string NameRelativeToModule { get { throw new cce.UnreachableException(); } } public Specification Decreases { get { throw new cce.UnreachableException(); } } public bool InferredDecreases { get { throw new cce.UnreachableException(); } set { throw new cce.UnreachableException(); } } public bool ContainsQuantifier { get { throw new cce.UnreachableException(); } set { throw new cce.UnreachableException(); } } } /// /// An IMethodCodeContext is a Method or IteratorDecl. /// public interface IMethodCodeContext : ICallable { List Outs { get; } Specification Modifies { get; } } /// /// Applies when we are not inside an ICallable. In particular, a NoContext is used to resolve the attributes of declarations with no other context. /// public class NoContext : ICodeContext { public readonly ModuleDefinition Module; public NoContext(ModuleDefinition module) { this.Module = module; } bool ICodeContext.IsGhost { get { return true; } } List ICodeContext.TypeArgs { get { return new List(); } } List ICodeContext.Ins { get { return new List(); } } Specification Decreases { get { return new Specification(null, null); } } ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } } bool ICodeContext.MustReverify { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } } public string FullSanitizedName { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } } public bool AllowsNontermination { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } } public bool ContainsQuantifier { get { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } set { Contract.Assume(false, "should not be called on NoContext"); throw new cce.UnreachableException(); } } } public class IteratorDecl : ClassDecl, IMethodCodeContext { public override string WhatKind { get { return "iterator"; } } public readonly List Ins; public readonly List Outs; public readonly Specification Reads; public readonly Specification Modifies; public readonly Specification Decreases; public readonly List Requires; public readonly List Ensures; public readonly List YieldRequires; public readonly List YieldEnsures; public readonly BlockStmt Body; public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } } public readonly IToken SignatureEllipsis; public readonly List OutsFields; public readonly List OutsHistoryFields; // these are the 'xs' variables public readonly List DecreasesFields; // filled in during resolution public SpecialField Member_Modifies; // filled in during resolution public SpecialField Member_Reads; // filled in during resolution public SpecialField Member_New; // filled in during resolution public Constructor Member_Init; // created during registration phase of resolution; its specification is filled in during resolution public Predicate Member_Valid; // created during registration phase of resolution; its specification is filled in during resolution public Method Member_MoveNext; // created during registration phase of resolution; its specification is filled in during resolution public readonly LocalVariable YieldCountVariable; bool containsQuantifier; public IteratorDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, List ins, List outs, Specification reads, Specification mod, Specification decreases, List requires, List ensures, List yieldRequires, List yieldEnsures, BlockStmt body, Attributes attributes, IToken signatureEllipsis) : base(tok, name, module, typeArgs, new List(), attributes, null) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(typeArgs != null); Contract.Requires(ins != null); Contract.Requires(outs != null); Contract.Requires(reads != null); Contract.Requires(mod != null); Contract.Requires(decreases != null); Contract.Requires(requires != null); Contract.Requires(ensures != null); Contract.Requires(yieldRequires != null); Contract.Requires(yieldEnsures != null); Ins = ins; Outs = outs; Reads = reads; Modifies = mod; Decreases = decreases; Requires = requires; Ensures = ensures; YieldRequires = yieldRequires; YieldEnsures = yieldEnsures; Body = body; SignatureEllipsis = signatureEllipsis; OutsFields = new List(); OutsHistoryFields = new List(); DecreasesFields = new List(); YieldCountVariable = new LocalVariable(tok, tok, "_yieldCount", new EverIncreasingType(), true); YieldCountVariable.type = YieldCountVariable.OptionalType; // resolve YieldCountVariable here } /// /// Returns the non-null expressions of this declaration proper (that is, do not include the expressions of substatements). /// Does not include the generated class members. /// public virtual IEnumerable SubExpressions { get { foreach (var e in Attributes.SubExpressions(Attributes)) { yield return e; } foreach (var e in Attributes.SubExpressions(Reads.Attributes)) { yield return e; } foreach (var e in Reads.Expressions) { yield return e.E; } foreach (var e in Attributes.SubExpressions(Modifies.Attributes)) { yield return e; } foreach (var e in Modifies.Expressions) { yield return e.E; } foreach (var e in Attributes.SubExpressions(Decreases.Attributes)) { yield return e; } foreach (var e in Decreases.Expressions) { yield return e; } foreach (var e in Requires) { yield return e.E; } foreach (var e in Ensures) { yield return e.E; } foreach (var e in YieldRequires) { yield return e.E; } foreach (var e in YieldEnsures) { yield return e.E; } } } /// /// This Dafny type exists only for the purpose of giving the yield-count variable a type, so /// that the type can be recognized during translation of Dafny into Boogie. It represents /// an integer component in a "decreases" clause whose order is (\lambda x,y :: x GREATER y), /// not the usual (\lambda x,y :: x LESS y AND 0 ATMOST y). /// public class EverIncreasingType : BasicType { [Pure] public override string TypeName(ModuleDefinition context) { return "_increasingInt"; } public override bool Equals(Type that) { return that.NormalizeExpand() is EverIncreasingType; } } bool ICodeContext.IsGhost { get { return false; } } List ICodeContext.TypeArgs { get { return this.TypeArgs; } } List ICodeContext.Ins { get { return this.Ins; } } List IMethodCodeContext.Outs { get { return this.Outs; } } Specification IMethodCodeContext.Modifies { get { return this.Modifies; } } IToken ICallable.Tok { get { return this.tok; } } string ICallable.NameRelativeToModule { get { return this.Name; } } Specification ICallable.Decreases { get { return this.Decreases; } } bool _inferredDecr; bool ICallable.InferredDecreases { set { _inferredDecr = value; } get { return _inferredDecr; } } bool ICodeContext.ContainsQuantifier { set { containsQuantifier = value; } get { return containsQuantifier; } } ModuleDefinition ICodeContext.EnclosingModule { get { return this.Module; } } bool ICodeContext.MustReverify { get { return false; } } public bool AllowsNontermination { get { return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr); } } } public abstract class MemberDecl : Declaration { public abstract string WhatKind { get; } public readonly bool HasStaticKeyword; public bool IsStatic { get { return HasStaticKeyword || (EnclosingClass is ClassDecl && ((ClassDecl)EnclosingClass).IsDefaultClass); } } public readonly bool IsGhost; public TopLevelDecl EnclosingClass; // filled in during resolution public MemberDecl RefinementBase; // filled in during the pre-resolution refinement transformation; null if the member is new here public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes, Declaration clonedFrom = null) : base(tok, name, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); HasStaticKeyword = hasStaticKeyword; IsGhost = isGhost; } /// /// Returns className+"."+memberName. Available only after resolution. /// public string FullName { get { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); return EnclosingClass.FullName + "." + Name; } } public string FullSanitizedName { get { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); return EnclosingClass.FullSanitizedName + "." + CompileName; } } public string FullSanitizedRefinementName { get { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); return EnclosingClass.FullSanitizedRefinementName + "." + CompileName; } } public string FullNameInContext(ModuleDefinition context) { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); return EnclosingClass.FullNameInContext(context) + "." + Name; } public override string CompileName { get { var nm = base.CompileName; if (this.Name == EnclosingClass.Name) { nm = "_" + nm; } return nm; } } public string FullCompileName { get { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); return EnclosingClass.FullCompileName + ".@" + CompileName; } } public virtual IEnumerable SubExpressions { get { yield break; } } } public class Field : MemberDecl { public override string WhatKind { get { return "field"; } } public readonly bool IsMutable; // says whether or not the field can ever change values public readonly bool IsUserMutable; // says whether or not code is allowed to assign to the field (IsUserMutable implies IsMutable) public readonly Type Type; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(Type != null); Contract.Invariant(!IsUserMutable || IsMutable); // IsUserMutable ==> IsMutable } public Field(IToken tok, string name, bool isGhost, Type type, Attributes attributes) : this(tok, name, isGhost, true, true, type, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); } public Field(IToken tok, string name, bool isGhost, bool isMutable, bool isUserMutable, Type type, Attributes attributes) : base(tok, name, false, isGhost, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); Contract.Requires(!isUserMutable || isMutable); IsMutable = isMutable; IsUserMutable = isUserMutable; Type = type; } } public class SpecialField : Field { public readonly string CompiledName; public readonly string PreString; public readonly string PostString; public SpecialField(IToken tok, string name, string compiledName, string preString, string postString, bool isGhost, bool isMutable, bool isUserMutable, Type type, Attributes attributes) : base(tok, name, isGhost, isMutable, isUserMutable, type, attributes) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(compiledName != null); Contract.Requires(preString != null); Contract.Requires(postString != null); Contract.Requires(!isUserMutable || isMutable); Contract.Requires(type != null); CompiledName = compiledName; PreString = preString; PostString = postString; } } public class DatatypeDestructor : SpecialField { public readonly DatatypeCtor EnclosingCtor; public readonly Formal CorrespondingFormal; public DatatypeDestructor(IToken tok, DatatypeCtor enclosingCtor, Formal correspondingFormal, string name, string compiledName, string preString, string postString, bool isGhost, Type type, Attributes attributes) : base(tok, name, compiledName, preString, postString, isGhost, false, false, type, attributes) { Contract.Requires(tok != null); Contract.Requires(enclosingCtor != null); Contract.Requires(correspondingFormal != null); Contract.Requires(name != null); Contract.Requires(compiledName != null); Contract.Requires(preString != null); Contract.Requires(postString != null); Contract.Requires(type != null); EnclosingCtor = enclosingCtor; CorrespondingFormal = correspondingFormal; } } public class OpaqueTypeDecl : TopLevelDecl, TypeParameter.ParentType { public override string WhatKind { get { return "opaque type"; } } public readonly TypeParameter TheType; public TypeParameter.EqualitySupportValue EqualitySupport { get { return TheType.EqualitySupport; } } public bool MustSupportEquality { get { return TheType.MustSupportEquality; } } [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(TheType != null && Name == TheType.Name); } public OpaqueTypeDecl(IToken tok, string name, ModuleDefinition module, TypeParameter.EqualitySupportValue equalitySupport, List typeArgs, Attributes attributes, Declaration clonedFrom = null) : base(tok, name, module, typeArgs, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(typeArgs != null); TheType = new OpaqueType_AsParameter(tok, name, equalitySupport, TypeArgs); } } public interface RedirectingTypeDecl : ICallable { string Name { get; } } public class NativeType { public readonly string Name; public readonly BigInteger LowerBound; public readonly BigInteger UpperBound; public readonly string Suffix; public readonly bool NeedsCastAfterArithmetic; public NativeType(string Name, BigInteger LowerBound, BigInteger UpperBound, string Suffix, bool NeedsCastAfterArithmetic) { Contract.Requires(Name != null); Contract.Requires(LowerBound != null); Contract.Requires(UpperBound != null); Contract.Requires(Suffix != null); this.Name = Name; this.LowerBound = LowerBound; this.UpperBound = UpperBound; this.Suffix = Suffix; this.NeedsCastAfterArithmetic = NeedsCastAfterArithmetic; } } public class NewtypeDecl : TopLevelDecl, RedirectingTypeDecl { public override string WhatKind { get { return "newtype"; } } public readonly Type BaseType; public readonly BoundVar Var; // can be null (if non-null, then object.ReferenceEquals(Var.Type, BaseType)) public readonly Expression Constraint; // is null iff Var is public NativeType NativeType; // non-null for fixed-size representations (otherwise, use BigIntegers for integers) public NewtypeDecl(IToken tok, string name, ModuleDefinition module, Type baseType, Attributes attributes, NewtypeDecl clonedFrom = null) : base(tok, name, module, new List(), attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(baseType != null); BaseType = baseType; } public NewtypeDecl(IToken tok, string name, ModuleDefinition module, BoundVar bv, Expression constraint, Attributes attributes, NewtypeDecl clonedFrom = null) : base(tok, name, module, new List(), attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(bv != null && bv.Type != null); BaseType = bv.Type; Var = bv; Constraint = constraint; } string RedirectingTypeDecl.Name { get { return Name; } } bool ICodeContext.IsGhost { get { return true; } } List ICodeContext.TypeArgs { get { return new List(); } } List ICodeContext.Ins { get { return new List(); } } ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } } bool ICodeContext.MustReverify { get { return false; } } bool ICodeContext.AllowsNontermination { get { return false; } } IToken ICallable.Tok { get { return tok; } } string ICallable.NameRelativeToModule { get { return Name; } } Specification ICallable.Decreases { get { // The resolver checks that a NewtypeDecl sits in its own SSC in the call graph. Therefore, // the question of what its Decreases clause is should never arise. throw new cce.UnreachableException(); } } bool ICallable.InferredDecreases { get { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases set { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases } bool ICodeContext.ContainsQuantifier { get { throw new cce.UnreachableException(); } set { throw new cce.UnreachableException(); } } public new NewtypeDecl ClonedFrom { get { return (NewtypeDecl)base.ClonedFrom; } } } public class TypeSynonymDecl : TopLevelDecl, RedirectingTypeDecl { public override string WhatKind { get { return "type synonym"; } } public readonly Type Rhs; public TypeSynonymDecl(IToken tok, string name, List typeArgs, ModuleDefinition module, Type rhs, Attributes attributes, TypeSynonymDecl clonedFrom = null) : base(tok, name, module, typeArgs, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(typeArgs != null); Contract.Requires(module != null); Contract.Requires(rhs != null); Rhs = rhs; } /// /// Returns the declared .Rhs but with formal type arguments replaced by the given actuals. /// public Type RhsWithArgument(List typeArgs) { Contract.Requires(typeArgs != null); Contract.Requires(typeArgs.Count == TypeArgs.Count); // Instantiate with the actual type arguments if (typeArgs.Count == 0) { // this optimization seems worthwhile return Rhs; } else { var subst = Resolver.TypeSubstitutionMap(TypeArgs, typeArgs); return Resolver.SubstType(Rhs, subst); } } string RedirectingTypeDecl.Name { get { return Name; } } bool ICodeContext.IsGhost { get { return false; } } List ICodeContext.TypeArgs { get { return TypeArgs; } } List ICodeContext.Ins { get { return new List(); } } ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } } bool ICodeContext.MustReverify {get { return false; } } bool ICodeContext.AllowsNontermination { get { return false; } } IToken ICallable.Tok { get { return tok; } } string ICallable.NameRelativeToModule { get { return Name; } } Specification ICallable.Decreases { get { // The resolver checks that a NewtypeDecl sits in its own SSC in the call graph. Therefore, // the question of what its Decreases clause is should never arise. throw new cce.UnreachableException(); } } bool ICallable.InferredDecreases { get { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases set { throw new cce.UnreachableException(); } // see comment above about ICallable.Decreases } bool ICodeContext.ContainsQuantifier { get { throw new cce.UnreachableException(); } set { throw new cce.UnreachableException(); } } } [ContractClass(typeof(IVariableContracts))] public interface IVariable { string Name { get; } string DisplayName { // what the user thinks he wrote get; } string UniqueName { get; } bool HasBeenAssignedUniqueName { // unique names are not assigned until the Translator; if you don't already know if that stage has run, this boolean method will tell you get; } string AssignUniqueName(FreshIdGenerator generator); string CompileName { get; } Type Type { get; } bool IsMutable { get; } bool IsGhost { get; } IToken Tok { get; } } [ContractClassFor(typeof(IVariable))] public abstract class IVariableContracts : IVariable { public string Name { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public string DisplayName { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public string UniqueName { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public bool HasBeenAssignedUniqueName { get { throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public string CompileName { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public Type Type { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); // this getter implementation is here only so that the Ensures contract can be given here } } public bool IsMutable { get { throw new NotImplementedException(); } } public bool IsGhost { get { throw new NotImplementedException(); } } public IToken Tok { get { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); } } public string AssignUniqueName(FreshIdGenerator generator) { Contract.Ensures(Contract.Result() != null); throw new NotImplementedException(); } } public abstract class NonglobalVariable : IVariable { public readonly IToken tok; readonly string name; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(tok != null); Contract.Invariant(name != null); Contract.Invariant(type != null); } public string Name { get { Contract.Ensures(Contract.Result() != null); return name; } } public string DisplayName { get { return LocalVariable.DisplayNameHelper(this); } } private string uniqueName; public string UniqueName { get { return uniqueName; } } public bool HasBeenAssignedUniqueName { get { return uniqueName != null; } } public string AssignUniqueName(FreshIdGenerator generator) { if (uniqueName == null) { uniqueName = generator.FreshId(Name + "#"); compileName = string.Format("_{0}_{1}", Compiler.FreshId(), CompilerizeName(name)); } return UniqueName; } static char[] specialChars = new char[] { '\'', '_', '?', '\\', '#' }; public static string CompilerizeName(string nm) { if ('0' <= nm[0] && nm[0] <= '9') { // the identifier is one that consists of just digits return "_" + nm; } string name = null; int i = 0; while (true) { int j = nm.IndexOfAny(specialChars, i); if (j == -1) { if (i == 0) { return nm; // this is the common case } else { return name + nm.Substring(i); } } else { string nxt = nm.Substring(i, j - i); name = name == null ? nxt : name + nxt; switch (nm[j]) { case '\'': name += "_k"; break; case '_': name += "__"; break; case '?': name += "_q"; break; case '\\': name += "_b"; break; case '#': name += "_h"; break; default: Contract.Assume(false); // unexpected character break; } i = j + 1; if (i == nm.Length) { return name; } } } } protected string compileName; public virtual string CompileName { get { if (compileName == null) { compileName = string.Format("_{0}_{1}", Compiler.FreshId(), CompilerizeName(name)); } return compileName; } } Type type; public Type SyntacticType { get { return type; } } // returns the non-normalized type public Type Type { get { Contract.Ensures(Contract.Result() != null); return type.Normalize(); } } public abstract bool IsMutable { get; } bool isGhost; // readonly after resolution public bool IsGhost { get { return isGhost; } set { isGhost = value; } } public IToken Tok { get { return tok; } } public NonglobalVariable(IToken tok, string name, Type type, bool isGhost) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); this.tok = tok; this.name = name; this.type = type; this.isGhost = isGhost; } } public class Formal : NonglobalVariable { public readonly bool InParam; // true to in-parameter, false for out-parameter public override bool IsMutable { get { return !InParam; } } public Formal(IToken tok, string name, Type type, bool inParam, bool isGhost) : base(tok, name, type, isGhost) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); InParam = inParam; } public bool HasName { get { return !Name.StartsWith("#"); } } public override string CompileName { get { if (compileName == null) { compileName = CompilerizeName(Name); } return compileName; } } } /// /// An ImplicitFormal is a parameter that is declared implicitly, in particular the "_k" depth parameter /// of each colemma (for use in the comethod body only, not the specification). /// public class ImplicitFormal : Formal { public ImplicitFormal(IToken tok, string name, Type type, bool inParam, bool isGhost) : base(tok, name, type, inParam, isGhost) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); } } [DebuggerDisplay("Bound<{name}>")] public class BoundVar : NonglobalVariable { public override bool IsMutable { get { return false; } } public BoundVar(IToken tok, string name, Type type) : base(tok, name, type, false) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(type != null); } } public class Function : MemberDecl, TypeParameter.ParentType, ICallable { public override string WhatKind { get { return "function"; } } public readonly bool IsProtected; public bool IsRecursive; // filled in during resolution public bool IsFueled; // filled in during resolution if anyone tries to adjust this function's fuel public readonly List TypeArgs; public readonly List Formals; public readonly Type ResultType; public readonly List Req; public readonly List Reads; public readonly List Ens; public readonly Specification Decreases; public Expression Body; // an extended expression; Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } } // is "false" for all Function objects that survive into resolution public readonly IToken SignatureEllipsis; public bool IsBuiltin; public Function OverriddenFunction; public bool containsQuantifier; public bool ContainsQuantifier { set { containsQuantifier = value; } get { return containsQuantifier; } } public override IEnumerable SubExpressions { get { foreach (var e in Req) { yield return e; } foreach (var e in Reads) { yield return e.E; } foreach (var e in Ens) { yield return e; } foreach (var e in Decreases.Expressions) { yield return e; } if (Body != null) { yield return Body; } } } public Type Type { get { // Note, the following returned type can contain type parameters from the function and its enclosing class return new ArrowType(tok, Formals.ConvertAll(f => f.Type), ResultType); } } public bool AllowsNontermination { get { return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr); } } /// /// The "AllCalls" field is used for non-FixpointPredicate, non-PrefixPredicate functions only (so its value should not be relied upon for FixpointPredicate and PrefixPredicate functions). /// It records all function calls made by the Function, including calls made in the body as well as in the specification. /// The field is filled in during resolution (and used toward the end of resolution, to attach a helpful "decreases" prefix to functions in clusters /// with co-recursive calls. /// public readonly List AllCalls = new List(); public enum CoCallClusterInvolvement { None, // the SCC containing the function does not involve any co-recursive calls IsMutuallyRecursiveTarget, // the SCC contains co-recursive calls, and this function is the target of some non-self recursive call CoRecursiveTargetAllTheWay, // the SCC contains co-recursive calls, and this function is the target only of self-recursive calls and co-recursive calls } public CoCallClusterInvolvement CoClusterTarget = CoCallClusterInvolvement.None; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(TypeArgs)); Contract.Invariant(cce.NonNullElements(Formals)); Contract.Invariant(ResultType != null); Contract.Invariant(cce.NonNullElements(Req)); Contract.Invariant(cce.NonNullElements(Reads)); Contract.Invariant(cce.NonNullElements(Ens)); Contract.Invariant(Decreases != null); } /// /// Note, functions are "ghost" by default; a non-ghost function is called a "function method". /// public Function(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost, List typeArgs, List formals, Type resultType, List req, List reads, List ens, Specification decreases, Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(formals)); Contract.Requires(resultType != null); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(cce.NonNullElements(reads)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); this.IsProtected = isProtected; this.IsFueled = false; // Defaults to false. Only set to true if someone mentions this function in a fuel annotation this.TypeArgs = typeArgs; this.Formals = formals; this.ResultType = resultType; this.Req = req; this.Reads = reads; this.Ens = ens; this.Decreases = decreases; this.Body = body; this.SignatureEllipsis = signatureEllipsis; if (attributes != null) { List args = Attributes.FindExpressions(attributes, "fuel"); if (args != null) { if (args.Count == 1) { LiteralExpr literal = args[0] as LiteralExpr; if (literal != null && literal.Value is BigInteger) { this.IsFueled = true; } } else if (args.Count == 2) { LiteralExpr literalLow = args[0] as LiteralExpr; LiteralExpr literalHigh = args[1] as LiteralExpr; if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) { this.IsFueled = true; } } } } } bool ICodeContext.IsGhost { get { return this.IsGhost; } } List ICodeContext.TypeArgs { get { return this.TypeArgs; } } List ICodeContext.Ins { get { return this.Formals; } } IToken ICallable.Tok { get { return this.tok; } } string ICallable.NameRelativeToModule { get { return EnclosingClass.Name + "." + Name; } } Specification ICallable.Decreases { get { return this.Decreases; } } bool _inferredDecr; bool ICallable.InferredDecreases { set { _inferredDecr = value; } get { return _inferredDecr; } } ModuleDefinition ICodeContext.EnclosingModule { get { return this.EnclosingClass.Module; } } bool ICodeContext.MustReverify { get { return false; } } [Pure] public bool IsFuelAware() { return IsRecursive || IsFueled; } } public class Predicate : Function { public override string WhatKind { get { return "predicate"; } } public enum BodyOriginKind { OriginalOrInherited, // this predicate definition is new (and the predicate may or may not have a body), or the predicate's body (whether or not it exists) is being inherited unmodified (from the previous refinement--it may be that the inherited body was itself an extension, for example) DelayedDefinition, // this predicate declaration provides, for the first time, a body--the declaration refines a previously declared predicate, but the previous one had no body Extension // this predicate extends the definition of a predicate with a body in a module being refined } public readonly BodyOriginKind BodyOrigin; public Predicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost, List typeArgs, List formals, List req, List reads, List ens, Specification decreases, Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(bodyOrigin == Predicate.BodyOriginKind.OriginalOrInherited || body != null); BodyOrigin = bodyOrigin; } } /// /// An PrefixPredicate is the inductive unrolling P# implicitly declared for every fixpoint-predicate P. /// public class PrefixPredicate : Function { public override string WhatKind { get { return "prefix predicate"; } } public readonly Formal K; public readonly FixpointPredicate FixpointPred; public PrefixPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, Formal k, List formals, List req, List reads, List ens, Specification decreases, Expression body, Attributes attributes, FixpointPredicate fixpointPred) : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, null, null) { Contract.Requires(k != null); Contract.Requires(fixpointPred != null); Contract.Requires(formals != null && 1 <= formals.Count && formals[0] == k); K = k; FixpointPred = fixpointPred; } } public abstract class FixpointPredicate : Function { public readonly List Uses = new List(); // filled in during resolution, used by verifier public PrefixPredicate PrefixPredicate; // filled in during resolution (name registration) public FixpointPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, new Specification(new List(), null), body, attributes, signatureEllipsis, clonedFrom) { } /// /// For the given call P(s), return P#[depth](s). The resulting expression shares some of the subexpressions /// with 'fexp' (that is, what is returned is not necessarily a clone). /// public FunctionCallExpr CreatePrefixPredicateCall(FunctionCallExpr fexp, Expression depth) { Contract.Requires(fexp != null); Contract.Requires(fexp.Function == this); Contract.Requires(depth != null); Contract.Ensures(Contract.Result() != null); var args = new List() { depth }; args.AddRange(fexp.Args); var prefixPredCall = new FunctionCallExpr(fexp.tok, this.PrefixPredicate.Name, fexp.Receiver, fexp.OpenParen, args); prefixPredCall.Function = this.PrefixPredicate; // resolve here prefixPredCall.TypeArgumentSubstitutions = new Dictionary(); var old_to_new = new Dictionary(); for (int i = 0; i < this.TypeArgs.Count; i++) { old_to_new[this.TypeArgs[i]] = this.PrefixPredicate.TypeArgs[i]; } foreach (var p in fexp.TypeArgumentSubstitutions) { prefixPredCall.TypeArgumentSubstitutions[old_to_new[p.Key]] = p.Value; } // resolved here. prefixPredCall.Type = fexp.Type; // resolve here prefixPredCall.CoCall = fexp.CoCall; // resolve here return prefixPredCall; } } public class InductivePredicate : FixpointPredicate { public override string WhatKind { get { return "inductive predicate"; } } public InductivePredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals, req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) { } } public class CoPredicate : FixpointPredicate { public override string WhatKind { get { return "copredicate"; } } public CoPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals, req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) { } } public class Method : MemberDecl, TypeParameter.ParentType, IMethodCodeContext { public override string WhatKind { get { return "method"; } } public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } } public readonly IToken SignatureEllipsis; public bool MustReverify; public readonly List TypeArgs; public readonly List Ins; public readonly List Outs; public readonly List Req; public readonly Specification Mod; public readonly List Ens; public readonly Specification Decreases; public BlockStmt Body; // Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution public bool IsRecursive; // filled in during resolution public bool IsTailRecursive; // filled in during resolution public readonly ISet AssignedAssumptionVariables = new HashSet(); public Method OverriddenMethod; public bool containsQuantifier; public override IEnumerable SubExpressions { get { foreach (var e in Req) { yield return e.E; } foreach (var e in Mod.Expressions) { yield return e.E; } foreach (var e in Ens) { yield return e.E; } foreach (var e in Decreases.Expressions) { yield return e; } } } [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(cce.NonNullElements(TypeArgs)); Contract.Invariant(cce.NonNullElements(Ins)); Contract.Invariant(cce.NonNullElements(Outs)); Contract.Invariant(cce.NonNullElements(Req)); Contract.Invariant(Mod != null); Contract.Invariant(cce.NonNullElements(Ens)); Contract.Invariant(Decreases != null); } public Method(IToken tok, string name, bool hasStaticKeyword, bool isGhost, [Captured] List typeArgs, [Captured] List ins, [Captured] List outs, [Captured] List req, [Captured] Specification mod, [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ins)); Contract.Requires(cce.NonNullElements(outs)); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(mod != null); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); this.TypeArgs = typeArgs; this.Ins = ins; this.Outs = outs; this.Req = req; this.Mod = mod; this.Ens = ens; this.Decreases = decreases; this.Body = body; this.SignatureEllipsis = signatureEllipsis; MustReverify = false; } bool ICodeContext.IsGhost { get { return this.IsGhost; } } List ICodeContext.TypeArgs { get { return this.TypeArgs; } } List ICodeContext.Ins { get { return this.Ins; } } List IMethodCodeContext.Outs { get { return this.Outs; } } Specification IMethodCodeContext.Modifies { get { return Mod; } } IToken ICallable.Tok { get { return this.tok; } } string ICallable.NameRelativeToModule { get { return EnclosingClass.Name + "." + Name; } } Specification ICallable.Decreases { get { return this.Decreases; } } bool _inferredDecr; bool ICallable.InferredDecreases { set { _inferredDecr = value; } get { return _inferredDecr; } } bool ICodeContext.ContainsQuantifier { set { containsQuantifier = value; } get { return containsQuantifier; } } ModuleDefinition ICodeContext.EnclosingModule { get { Contract.Assert(this.EnclosingClass != null); // this getter is supposed to be called only after signature-resolution is complete return this.EnclosingClass.Module; } } bool ICodeContext.MustReverify { get { return this.MustReverify; } } public bool AllowsNontermination { get { return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr); } } public override string CompileName { get { var nm = base.CompileName; if (IsStatic && nm == "Main" && !Dafny.Compiler.IsMain(this)) { // for a static method that is named "Main" but is not a legal "Main" method, // change its name. nm = EnclosingClass.Name + "_" + nm; } return nm; } } } public class Lemma : Method { public override string WhatKind { get { return "lemma"; } } public Lemma(IToken tok, string name, bool hasStaticKeyword, [Captured] List typeArgs, [Captured] List ins, [Captured] List outs, [Captured] List req, [Captured] Specification mod, [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { } } public class Constructor : Method { public override string WhatKind { get { return "constructor"; } } public Constructor(IToken tok, string name, [Captured] List typeArgs, [Captured] List ins, [Captured] List req, [Captured] Specification mod, [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, false, false, typeArgs, ins, new List(), req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ins)); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(mod != null); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); } public bool HasName { get { return Name != "_ctor"; } } } /// /// A PrefixLemma is the inductive unrolling M# implicitly declared for every colemma M. /// public class PrefixLemma : Method { public override string WhatKind { get { return "prefix lemma"; } } public readonly Formal K; public readonly FixpointLemma FixpointLemma; public PrefixLemma(IToken tok, string name, bool hasStaticKeyword, List typeArgs, Formal k, List ins, List outs, List req, Specification mod, List ens, Specification decreases, BlockStmt body, Attributes attributes, FixpointLemma fixpointLemma) : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, null) { Contract.Requires(k != null); Contract.Requires(ins != null && 1 <= ins.Count && ins[0] == k); Contract.Requires(fixpointLemma != null); K = k; FixpointLemma = fixpointLemma; } } public abstract class FixpointLemma : Method { public PrefixLemma PrefixLemma; // filled in during resolution (name registration) public FixpointLemma(IToken tok, string name, bool hasStaticKeyword, List typeArgs, List ins, [Captured] List outs, List req, [Captured] Specification mod, List ens, Specification decreases, BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom) : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ins)); Contract.Requires(cce.NonNullElements(outs)); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(mod != null); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); } } public class InductiveLemma : FixpointLemma { public override string WhatKind { get { return "inductive lemma"; } } public InductiveLemma(IToken tok, string name, bool hasStaticKeyword, List typeArgs, List ins, [Captured] List outs, List req, [Captured] Specification mod, List ens, Specification decreases, BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ins)); Contract.Requires(cce.NonNullElements(outs)); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(mod != null); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); } } public class CoLemma : FixpointLemma { public override string WhatKind { get { return "colemma"; } } public CoLemma(IToken tok, string name, bool hasStaticKeyword, List typeArgs, List ins, [Captured] List outs, List req, [Captured] Specification mod, List ens, Specification decreases, BlockStmt body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); Contract.Requires(cce.NonNullElements(ins)); Contract.Requires(cce.NonNullElements(outs)); Contract.Requires(cce.NonNullElements(req)); Contract.Requires(mod != null); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(decreases != null); } } // ------------------------------------------------------------------------------------------------------ public abstract class Statement { public readonly IToken Tok; public readonly IToken EndTok; // typically a terminating semi-colon or end-curly-brace public LList