string TypeName(Type type, TextWriter wr) { Contract.Requires(type != null); Contract.Ensures(Contract.Result<string>() != null); var xType = type.NormalizeExpand(); if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type return "object"; } if (xType is BoolType) { return "bool"; } else if (xType is CharType) { return "char"; } else if (xType is IntType) { return "BigInteger"; } else if (xType is RealType) { return "Dafny.BigRational"; } else if (xType.AsNewtype != null) { NativeType nativeType = xType.AsNewtype.NativeType; if (nativeType != null) { return nativeType.Name; } return TypeName(xType.AsNewtype.BaseType, wr); } else if (xType is ObjectType) { return "object"; } else if (xType.IsArrayType) { ArrayClassDecl at = xType.AsArrayType; Contract.Assert(at != null); // follows from type.IsArrayType Type elType = UserDefinedType.ArrayElementType(xType); string name = TypeName(elType, wr) + "["; for (int i = 1; i < at.Dims; i++) { name += ","; } return name + "]"; } else if (xType is UserDefinedType) { var udt = (UserDefinedType)xType; var s = udt.FullCompileName; var rc = udt.ResolvedClass; if (DafnyOptions.O.IronDafny && !(xType is ArrowType) && rc != null && rc.Module != null && !rc.Module.IsDefaultModule) { while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { if (rc.ClonedFrom != null) { rc = (TopLevelDecl)rc.ClonedFrom; } else { Contract.Assert(rc.ExclusiveRefinement != null); rc = rc.ExclusiveRefinement; } } s = rc.FullCompileName; } return TypeName_UDT(s, udt.TypeArgs, wr); } else if (xType is SetType) { Type argType = ((SetType)xType).Arg; if (argType is ObjectType) { Error("compilation of set<object> is not supported; consider introducing a ghost", wr); } return DafnySetClass + "<" + TypeName(argType, wr) + ">"; } else if (xType is SeqType) { Type argType = ((SeqType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", wr); } return DafnySeqClass + "<" + TypeName(argType, wr) + ">"; } else if (xType is MultiSetType) { Type argType = ((MultiSetType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", wr); } return DafnyMultiSetClass + "<" + TypeName(argType, wr) + ">"; } else if (xType is MapType) { Type domType = ((MapType)xType).Domain; Type ranType = ((MapType)xType).Range; if (domType is ObjectType || ranType is ObjectType) { Error("compilation of map<object, _> or map<_, object> is not supported; consider introducing a ghost", wr); } return DafnyMapClass + "<" + TypeName(domType, wr) + "," + TypeName(ranType, wr) + ">"; } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } }
string DefaultValue(Type type, TextWriter wr) { Contract.Requires(type != null); Contract.Ensures(Contract.Result<string>() != null); var xType = type.NormalizeExpand(); if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type return "null"; } if (xType is BoolType) { return "false"; } else if (xType is CharType) { return "'D'"; } else if (xType is IntType) { return "BigInteger.Zero"; } else if (xType is RealType) { return "Dafny.BigRational.ZERO"; } else if (xType.AsNewtype != null) { if (xType.AsNewtype.NativeType != null) { return "0"; } return DefaultValue(xType.AsNewtype.BaseType, wr); } else if (xType.IsRefType) { return string.Format("({0})null", TypeName(xType, wr)); } else if (xType.IsDatatype) { var udt = (UserDefinedType)xType; var s = "@" + udt.FullCompileName; var rc = udt.ResolvedClass; if (DafnyOptions.O.IronDafny && !(xType is ArrowType) && rc != null && rc.Module != null && !rc.Module.IsDefaultModule) { while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { if (rc.ClonedFrom != null) { rc = (TopLevelDecl)rc.ClonedFrom; } else { Contract.Assert(rc.ExclusiveRefinement != null); rc = rc.ExclusiveRefinement; } } s = "@" + rc.FullCompileName; } if (udt.TypeArgs.Count != 0) { s += "<" + TypeNames(udt.TypeArgs, wr) + ">"; } return string.Format("new {0}()", s); } else if (xType.IsTypeParameter) { var udt = (UserDefinedType)xType; string s = "default(@" + udt.FullCompileName; if (udt.TypeArgs.Count != 0) { s += "<" + TypeNames(udt.TypeArgs, wr) + ">"; } s += ")"; return s; } else if (xType is SetType) { return DafnySetClass + "<" + TypeName(((SetType)xType).Arg, wr) + ">.Empty"; } else if (xType is MultiSetType) { return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)xType).Arg, wr) + ">.Empty"; } else if (xType is SeqType) { return DafnySeqClass + "<" + TypeName(((SeqType)xType).Arg, wr) + ">.Empty"; } else if (xType is MapType) { return TypeName(xType, wr) + ".Empty"; } else if (xType is ArrowType) { return "null"; } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } }
// KRemlin extraction does not support some types. Where possible, references to them are // skipped, rather than emitting Kremlin JSON for C extraction that will not execute. bool IsUnsupportedType(Type type) { var xType = type.NormalizeExpand(); if (xType is IntType || xType is RealType || xType is BitvectorType || xType is ObjectType || xType is SetType || xType is SeqType || xType is MultiSetType || xType is MapType) { return true; } return false; }
void WriteTypeWidth(Type type) { Contract.Requires(type != null); Contract.Ensures(Contract.Result<string>() != null); Formatting old = j.Formatting; j.Formatting = Formatting.None; using (WriteArray()) { var xType = type.NormalizeExpand(); if (xType is TypeProxy) { j.WriteComment("BUGBUG Width of TypeProxy not supported"); // bugbug: implement j.WriteValue("0"); } else if (xType is BoolType) { j.WriteValue(KremlinAst.Bool); } else if (xType is CharType) { // bugbug: is this the right way to express a Dafny char? j.WriteValue(KremlinAst.Int8); } else if (xType is IntType) { var it = (IntType)xType; j.WriteComment("BUGBUG Dafny IntType is unsupported"); // bugbug: implement } else if (xType is RealType) { j.WriteComment("BUGBUG Dafny RealType is unsupported"); // bugbug: implement } else if (xType.AsNewtype != null) { NativeType nativeType = xType.AsNewtype.NativeType; if (nativeType != null) { j.WriteValue(nativeType.KremlinType()); } else { WriteTypeWidth(xType.AsNewtype.BaseType); } } else if (xType is ObjectType) { j.WriteComment("BUGBUG Dafny ObjectType is unsupported"); // bugbug: implement } else if (xType.IsArrayType) { j.WriteComment("BUGBUG Dafny IsArrayType is unsupported"); // bugbug: implement } else if (xType is UserDefinedType) { j.WriteComment("BUGBUG Dafny UserDefinedType is unsupported"); // bugbug: implement } else if (xType is SetType) { Type argType = ((SetType)xType).Arg; if (argType is ObjectType) { Error("compilation of set<object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG SetType is unsupported"); // bugbug: implement } else if (xType is SeqType) { Type argType = ((SeqType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", j); } WriteTypeName(((SeqType)xType).Arg); } else if (xType is MultiSetType) { Type argType = ((MultiSetType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG MultiSetType is unsupported"); // bugbug: implement } else if (xType is MapType) { Type domType = ((MapType)xType).Domain; Type ranType = ((MapType)xType).Range; if (domType is ObjectType || ranType is ObjectType) { Error("compilation of map<object, _> or map<_, object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG MapType is unsupported"); // bugbug: implement } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } } j.Formatting = old; }
void WriteTypeName(Type type) { Contract.Requires(type != null); Contract.Ensures(Contract.Result<string>() != null); Formatting old = j.Formatting; j.Formatting = Formatting.None; using (WriteArray()) { var xType = type.NormalizeExpand(); if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type j.WriteValue(KremlinAst.TUnit); } else if (xType is BoolType) { j.WriteValue(KremlinAst.TBool); } else if (xType is CharType) { // bugbug: is this the right way to express a Dafny char? j.WriteValue(KremlinAst.TInt); using (WriteArray()) { j.WriteValue(KremlinAst.Int8); } } else if (xType is IntType) { var it = (IntType)xType; // bugbug: A Dafny IntType is an infinite-precision integer. Add // runtime support for them as needed. j.WriteValue(KremlinAst.TQualified); using (WriteArray()) { using (WriteArray()) { j.WriteValue("Dafny"); } j.WriteValue("BigInt"); } } else if (xType is RealType) { j.WriteComment("BUGBUG Dafny RealType is unsupported"); // bugbug: implement } else if (xType is BitvectorType) { j.WriteComment("BUGBUG Dafny BitvectorType is unsupported"); // bugbug: implement } else if (xType.AsNewtype != null) { NativeType nativeType = xType.AsNewtype.NativeType; if (nativeType != null) { j.WriteValue(KremlinAst.TInt); using (WriteArray()) { j.WriteValue(nativeType.KremlinType()); } } else { WriteTypeName(xType.AsNewtype.BaseType); } } else if (xType is ObjectType) { j.WriteComment("BUGBUG Dafny ObjectType is unsupported"); // bugbug: implement } else if (xType.IsArrayType) { ArrayClassDecl at = xType.AsArrayType; Contract.Assert(at != null); // follows from type.IsArrayType Type elType = UserDefinedType.ArrayElementType(xType); j.WriteValue(KremlinAst.TBuf); WriteTypeName(elType); // bugbug: at.Dims is currently ignored } else if (xType is UserDefinedType) { var udt = (UserDefinedType)xType; var s = udt.FullName; var rc = udt.ResolvedClass; if (DafnyOptions.O.IronDafny && !(xType is ArrowType) && rc != null && rc.Module != null && !rc.Module.IsDefaultModule) { while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { if (rc.ClonedFrom != null) { rc = (TopLevelDecl)rc.ClonedFrom; } else { Contract.Assert(rc.ExclusiveRefinement != null); rc = rc.ExclusiveRefinement; } } s = rc.FullName; } WriteTypeName_UDT(s, udt.TypeArgs); } else if (xType is SetType) { Type argType = ((SetType)xType).Arg; if (argType is ObjectType) { Error("compilation of set<object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG SetType is unsupported"); // bugbug: implement } else if (xType is SeqType) { Type argType = ((SeqType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", j); } j.WriteValue(KremlinAst.TBuf); WriteTypeName(argType); } else if (xType is MultiSetType) { Type argType = ((MultiSetType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq<object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG MultiSetType is unsupported"); // bugbug: implement } else if (xType is MapType) { Type domType = ((MapType)xType).Domain; Type ranType = ((MapType)xType).Range; if (domType is ObjectType || ranType is ObjectType) { Error("compilation of map<object, _> or map<_, object> is not supported; consider introducing a ghost", j); } j.WriteComment("BUGBUG MapType is unsupported"); // bugbug: implement } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } } j.Formatting = old; }
// Write out a default value as an expr void WriteDefaultValue(Type type) { Contract.Requires(type != null); Contract.Ensures(Contract.Result<string>() != null); var xType = type.NormalizeExpand(); if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type WriteEUnit(); } if (xType is BoolType) { var old = j.Formatting; j.Formatting = Formatting.None; using (WriteArray()) { j.WriteValue(KremlinAst.EConstant); using (WriteArray()) { j.WriteValue(KremlinAst.TBool); j.WriteValue(false); } } j.Formatting = old; } else if (xType is CharType) { var old = j.Formatting; j.Formatting = Formatting.None; using (WriteArray()) { j.WriteValue(KremlinAst.EConstant); using (WriteArray()) { j.WriteValue(KremlinAst.TInt); j.WriteValue((int)'D'); } } j.Formatting = old; } else if (xType is IntType) { var it = (IntType)xType; WriteEAbort("BUGBUG Dafny IntType is unsupported"); // bugbug: implement } else if (xType is RealType) { WriteEAbort("BUGBUG Dafny RealType is unsupported"); // bugbug: implement } else if (xType is BitvectorType) { WriteEAbort("BUGBUG Dafny BitvectorType is unsupported"); // bugbug: implement } else if (xType.AsNewtype != null) { if (xType.AsNewtype.NativeType != null) { var nativeType = xType.AsNewtype.NativeType; var old = j.Formatting; j.Formatting = Formatting.None; using (WriteArray()) { j.WriteValue(KremlinAst.EConstant); using (WriteArray()) { // of K.t using (WriteArray()) { j.WriteValue(nativeType.KremlinType()); } j.WriteValue("0"); } } j.Formatting = old; } else { WriteDefaultValue(xType.AsNewtype.BaseType); } } else if (xType.IsArrayType) { ArrayClassDecl at = xType.AsArrayType; Contract.Assert(at != null); // follows from type.IsArrayType using (WriteArray()) { j.WriteValue(KremlinAst.EAny); } } else if (xType.IsRefType) { using (WriteArray()) { j.WriteValue(KremlinAst.EAny); } } else if (xType.IsDatatype) { var udt = (UserDefinedType)xType; var s = udt.FullName; var rc = udt.ResolvedClass; if (DafnyOptions.O.IronDafny && !(xType is ArrowType) && rc != null && rc.Module != null && !rc.Module.IsDefaultModule) { while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { if (rc.ClonedFrom != null) { rc = (TopLevelDecl)rc.ClonedFrom; } else { Contract.Assert(rc.ExclusiveRefinement != null); rc = rc.ExclusiveRefinement; } } s = rc.FullName; } using (WriteArray()) { if (udt.TypeArgs.Count != 0) { WriteEAbort("Udt with TypeArgs is not supported"); // bugbug: implement } else { IndDatatypeDecl dcl = rc as IndDatatypeDecl; j.WriteValue(KremlinAst.EBufCreateL); using (WriteArray()) { // of expr list using (WriteArray()) { j.WriteValue(KremlinAst.EFlat); using (WriteArray()) { // (lident list of (ident * expr)) WriteLident(udt); using (WriteArray()) { int i = 0; foreach (var arg in dcl.DefaultCtor.Formals) { if (arg.IsGhost) { continue; } using (WriteArray()) { j.WriteValue(FormalName(arg, i)); // ident WriteDefaultValue(arg.Type); // expr } } } } } } } } } else if (xType.IsTypeParameter) { WriteEAbort("BUGBUG Dafny TypeParameter is unsupported"); // bugbug: implement } else if (xType is SetType) { WriteEAbort("BUGBUG Dafny SetType is unsupported"); // bugbug: implement } else if (xType is MultiSetType) { WriteEAbort("BUGBUG Dafny MultiSetType is unsupported"); // bugbug: implement } else if (xType is SeqType) { Type argType = ((SeqType)xType).Arg; using (WriteArray()) { j.WriteValue(KremlinAst.EAny); } } else if (xType is MapType) { WriteEAbort("BUGBUG Dafny MapType is unsupported"); // bugbug: implement } else if (xType is ArrowType) { WriteEAbort("BUGBUG Dafny ArrowType is unsupported"); // bugbug: implement } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } }
// Check that two resolved types are the same in a similar context (the same type parameters, method, class, etc.) // Assumes that prev is in a previous refinement, and next is in some refinement. Note this is not communative. public static bool ResolvedTypesAreTheSame(Type prev, Type next) { Contract.Requires(prev != null); Contract.Requires(next != null); prev = prev.NormalizeExpand(); next = next.NormalizeExpand(); if (prev is TypeProxy || next is TypeProxy) return false; if (prev is BoolType) { return next is BoolType; } else if (prev is CharType) { return next is CharType; } else if (prev is IntType) { if (next is IntType) { return (prev is NatType) == (next is NatType); } else return false; } else if (prev is RealType) { return next is RealType; } else if (prev is ObjectType) { return next is ObjectType; } else if (prev is SetType) { return next is SetType && ((SetType)prev).Finite == ((SetType)next).Finite && ResolvedTypesAreTheSame(((SetType)prev).Arg, ((SetType)next).Arg); } else if (prev is MultiSetType) { return next is MultiSetType && ResolvedTypesAreTheSame(((MultiSetType)prev).Arg, ((MultiSetType)next).Arg); } else if (prev is MapType) { return next is MapType && ((MapType)prev).Finite == ((MapType)next).Finite && ResolvedTypesAreTheSame(((MapType)prev).Domain, ((MapType)next).Domain) && ResolvedTypesAreTheSame(((MapType)prev).Range, ((MapType)next).Range); } else if (prev is SeqType) { return next is SeqType && ResolvedTypesAreTheSame(((SeqType)prev).Arg, ((SeqType)next).Arg); } else if (prev is UserDefinedType) { if (!(next is UserDefinedType)) { return false; } UserDefinedType aa = (UserDefinedType)prev; UserDefinedType bb = (UserDefinedType)next; if (aa.ResolvedClass != null && aa.ResolvedClass.Name == bb.ResolvedClass.Name) { // these are both resolved class/datatype types Contract.Assert(aa.TypeArgs.Count == bb.TypeArgs.Count); for (int i = 0; i < aa.TypeArgs.Count; i++) if (!ResolvedTypesAreTheSame(aa.TypeArgs[i], bb.TypeArgs[i])) return false; return true; } else if (aa.ResolvedParam != null && bb.ResolvedParam != null) { // these are both resolved type parameters Contract.Assert(aa.TypeArgs.Count == 0 && bb.TypeArgs.Count == 0); // Note that this is only correct if the two types occur in the same context, ie. both from the same method // or class field. return aa.ResolvedParam.PositionalIndex == bb.ResolvedParam.PositionalIndex && aa.ResolvedParam.IsToplevelScope == bb.ResolvedParam.IsToplevelScope; } else if (aa.ResolvedParam.IsAbstractTypeDeclaration && bb.ResolvedClass != null) { return (aa.ResolvedParam.Name == bb.ResolvedClass.Name); } else { // something is wrong; either aa or bb wasn't properly resolved, or they aren't the same return false; } } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } }